Please find the error! - C programming

This code runs fine :

int main()
{

char *a[]={"error 1\n",
          "error 2\n",
          "error 3\n",
          "error 4\n"};

printf("%c",*(*(a+1)+3));
}

Gives the output as : o

But as soon as I write:

int main()
{

char *a[]={"error 1\n",
          "error 2\n",
          "error 3\n",
          "error 4\n"};

*(*(a+1)+3)='y';
printf("%c",*(*(a+1)+3));
}

The expression before the printf() crashes the program on execution.
Why? It’s the same expression which is being printed, so why can’t I modify the value from ‘o’ to ‘y’ ?

Please help!


int main(void){
	char \*a[]={"error 1\n",
               "error 2\n",
               "error 3\n",
               "error 4\n"
              }; 
	//\*(\*(a+1)+3)='y';   //will result into error, reason is given in the explanation
	printf("%c\n",\*(\*(a+1)+3));
	\*(a+1)="error 9\n";
	printf("%s\n",\*(a+1));	

	char b[4][10]={"error 1\n",
                   "error 2\n",
                   "error 3\n",
                   "error 4\n"
                   }; 
	\*(\*(b+1)+3)='y';
        //b\[1]\[3]='y';
	printf("%c\n",\*(\*(b+1)+3));

	char \**c={"error 1\n",
              "error 2\n",
              "error 3\n",
              "error 4\n"
              };          
	\*(\*(c+1)+3)='y';
	printf("%c\n",\*(\*(c+1)+3));
	return(0);
}


The output is :

o

error 9


y

y

Check this on ideone here.

Now, how to explain this WEIRD behavior !!!, let’s see what is actually happening internally.

In the first case ( situation faced by you ) :

char *a[]={"error 1\n",
          "error 2\n",
          "error 3\n",
          "error 4\n"};

In brief, this declaration is associated with static storage duration, meaning that the memory for it is allocated when the program starts up and remains allocated until the program terminates. Attempting to modify the contents of a string literal invokes undefined behavior.
The memory diagram for here is given below,



       *a[]
( pointer to array )    0   1   2   3   4   5   6     7     8   9
    +--------+        +---+---+---+---+---+---+---+------+----+---+
    |      --|------->| e | r | r | o | r |   | 1 | '\n' |'\0'|   |
    +--------+        +---+---+---+---+---+---+---+------+----+---+
    |      --|------->| e | r | r | o | r |   | 2 | '\n' |'\0'|   |
    +--------+        +---+---+---+---+---+---+---+------+----+---+
    |      --|------->| e | r | r | o | r |   | 3 | '\n' |'\0'|   |
    +--------+        +---+---+---+---+---+---+---+------+----+---+
    |      --|------->| e | r | r | o | r |   | 4 | '\n' |'\0'|   |
    +--------+        +---+---+---+---+---+---+---+------+----+---+


Here, a[] is an array of char and the array is initialized by copying the members of the given string literal into the array. Then *a[] declares a to be a pointer to one or more (in this case more) chars and points it directly at a fixed (read-only) location containing the string ( array of chars ) literals “error n_i\n”.

So, char *a[] will place the contents of each row in the read-only parts of the memory and make a pointer to that, making any writing operation on this memory illegal.

In other contexts, char *a[] allocates a pointer to arrays. The compiler secretly allocates a static anonymous array to hold the string ( character array ) literals.

Note that you must not ever attempt to modify the contents of this anonymous array via such pointer; the effects are undefined (often leads to program crash). So modifying the content using ((a+1)+3)=‘y’; is a dangerous in this case.

In the second case ( char b[4][10] ) :

The memory diagram for this case is,


b[][] =

      0   1   2   3   4   5   6     7     8   9
    +---+---+---+---+---+---+---+------+----+---+
    | e | r | r | o | r |   | 1 | '\n' |'\0'|   |
    +---+---+---+---+---+---+---+------+----+---+
    | e | r | r | o | r |   | 2 | '\n' |'\0'|   |
    +---+---+---+---+---+---+---+------+----+---+
    | e | r | r | o | r |   | 3 | '\n' |'\0'|   |
    +---+---+---+---+---+---+---+------+----+---+
    | e | r | r | o | r |   | 4 | '\n' |'\0'|   |
    +---+---+---+---+---+---+---+------+----+---+


We are declaring char b[4][10] in a straight forward way by which the literal strings reside in read-only memory and are also copied to newly allocated memory on the stack. Thus operations like ((b+1)+3)=‘y’; or b1=‘y’; are perfectly valid.

In the third case ( char **c ) :

We define c as char **c, this is a simple pointer to pointer to char, with static storage duration, meaning that the memory for it is allocated when the program starts up and remains allocated until the program terminates. So all alter/modification operations like ((c+1)+3)=‘y’; are valid as we are traversing through each characters using direct pointers.

A few advance points to note here:

  1. In both the three situations, literals are stored in “read-only parts of the memory” , in case of example with the array points there, the example with the 2-D array copies the characters to the array elements.
  2. In the given example, literal string does not necessarily exist in memory as a single contiguous object at all, it’s just an initialiser, the compiler could quite reasonably emit a series of “load immediate byte” instructions that contain the character values embedded within them.
  3. Here “read-only parts of the memory” doesn’t necessarily have to be in read-only memory (some implementations have no MMUs, for example). The n1362 c1x draft simply states that modifying such an array causes undefined behavior.

I guess now you can realize why people say pointer concept is difficult. : D
You may want to check this awesome SO link

5 Likes

till i understand “error 1\n” is const type so you cannot modify its value.It is in read only memory.

char *a = "hello";
 printf("%c\n", *(a+4));
 *(a+4) = 't';
 printf("%c", *(a+4));

this will also have same problem because “hello” it self is const type.

Almost exactly similar reason, read only.

So much detailed answer, just like how I wanted! Thanks!

This example is great for testing and learning purpose!
This concept can be explained much better through the example that you provided :slight_smile: Thanks!