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.
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).
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.
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?
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);
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With