Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between char*str={"foo",...} and char str[][5]={"foo",...} array definitions?

Case 1: When I write

char*str={"what","is","this"}; 

then str[i]="newstring"; is valid whereas str[i][j]='j'; is invalid.

Case 2: When I write

char str[][5]={"what","is","this"}; 

then str[i]="newstring"; is not valid whereas str[i][j]='J'; is valid.

Why is it so? I am a beginner who already get very confused after reading the other answers.

like image 854
Ashish Dogra Avatar asked Jan 18 '18 07:01

Ashish Dogra


People also ask

What is the difference between char * and char array?

The main difference between them is that the first is an array and the other one is a pointer. The array owns its contents, which happen to be a copy of "Test" , while the pointer simply refers to the contents of the string (which in this case is immutable).

What is the difference between char * and char *?

Difference between char s[] and char *s in CThe s[] is an array, but *s is a pointer. For an example, if two declarations are like char s[20], and char *s respectively, then by using sizeof() we will get 20, and 4. The first one will be 20 as it is showing that there are 20 bytes of data.

What is the difference between char * str and char str []?

char *str[] is an array of many values, each value in the array is a char *str, as above. So, it is an array of null-terminated C strings. char str[] is an array of characters. How do you write a program which will take a char array from a user and check if it exits in characters or not?

What does char * str mean in C?

function (char *str) is the same as function (char str[]) and are functions that take char array as a parameter . function (char *str[]) is a function that take an array of char array as parameter. These function can be called using pointers example: function (char *str[]) char **x .... function (x);


2 Answers

The memory layout is different:

char* str[] = {"what", "is", "this"};      str +--------+      +-----+ | pointer| ---> |what0| +--------+      +-----+   +---+ | pointer| -------------> |is0| +--------+                +---+    +-----+ | pointer| ----------------------> |this0| +--------+                         +-----+ 

In this memory layout, str is an array of pointers to the individual strings. Usually, these individual strings will reside in static storage, and it is an error to try to modify them. In the graphic, I used 0 to denote the terminating null bytes.

char str[][5] = {"what", "is", "this"};    str +-----+ |what0| +-----+ |is000| +-----+ |this0| +-----+ 

In this case, str is a contiguous 2D array of characters located on the stack. The strings are copied into this memory area when the array is initialized, and the individual strings are padded with zero bytes to give the array a regular shape.

These two memory layout are fundamentally incompatible with each other. You cannot pass either to a function that expects a pointer to the other. However, access to the individual strings is compatible. When you write str[1], you get a char* to the first character of a memory region containing the bytes is0, i.e. a C string.

In the first case, it is clear that this pointer is simply loaded from memory. In the second case, the pointer is created via array-pointer-decay: str[1] actually denotes an array of exactly five bytes (is000), which immediately decays into a pointer to its first element in almost all contexts. However, I believe that a full explanation of the array-pointer-decay is beyond the scope of this answer. Google array-pointer-decay if you are curious.

like image 33
cmaster - reinstate monica Avatar answered Sep 17 '22 13:09

cmaster - reinstate monica


First of all: A suggestion: Please read about arrays are not pointers and vice-versa!!

That said, to enlighten this particular scenario,

  • In the first case,

    char*str={"what","is","this"}; 

    does not do what you think it does. It is a constraint violation, requiring a diagnostic from any conforming C implementation, as per chapter§6.7.9/P2:

    No initializer shall attempt to provide a value for an object not contained within the entity being initialized.

    If you enable warnings, you'd (at least) see

    warning: excess elements in scalar initializer

      char*str={"what","is","this"}; 

    However, a(ny) compiler with strict conformance turned on, should refuse to compile the code. In case, the compiler chose to compile and produce a binary anyway, the behavior is not withing the scope of definition of C language, it's up to the compiler implementation (and thus, can vary widely).

    In this case, compiler decided this statement to make functionally only same as char*str= "what";

    So, here str is a pointer to a char, which points to a string literal. You can re-assign to the pointer,

    str="newstring";  //this is valid 

    but, a statement like

     str[i]="newstring"; 

    would be invalid, as here, a pointer type is attempted to be converted and stored into a char type, where the types are not compatible. The compiler should throw a warning about the invalid conversion in this case.

    Thereafter, a statement like

    str[i][j]='J'; // compiler error 

    is syntactically invalid, as you're using the Array subscripting [] operator on something which is not "pointer to complete object type", like

    str[i][j] = ...       ^^^------------------- cannot use this ^^^^^^ --------------------- str[i] is of type 'char',                               not a pointer to be used as the operand for [] operator. 
  • On the other hand, in second case,

    str is an array of arrays. You can change individual array elements,

     str[i][j]='J'; // change individual element, good to go. 

    but you cannot assign to an array.

     str[i]="newstring";  // nopes, array type is not an lvalue!! 

  • Finally, considering you meant to write (as seen in comments)

    char* str[ ] ={"what","is","this"}; 

    in your first case, the same logic for arrays hold. This makes str an array of pointers. So, the array members, are assignable, so,

    str[i]="newstring";  // just overwrites the previous pointer 

    is perfectly OK. However, the pointers, which are stored as array members, are pointers to string literal, so for the very same reason mentioned above, you invoke undefined behavior, when you want to modify one of the elements of the memory belonging to the string literal

     str[i][j]='j';   //still invalid, as above. 
like image 133
Sourav Ghosh Avatar answered Sep 16 '22 13:09

Sourav Ghosh