Array of Pointers in C how is the operator [ ] used - arrays

Hello I am new to C and its pointers. I thought I understood pointers untill I stumbled upon Array of Pointers.
Why is the output of these two code fragements exactly the same. I would expect that my normal array gives me the values. And the array that holds of pointers gives me the addresse of the values.
char *array[] = {'a','b','c','d'};
for(int i=0; i<4; i++){
printf("%c\n", array[i]);
}
char array[] = {'a','b','c','d'};
for(int i=0; i<4; i++){
printf("%c\n", array[i]);
}
I know that '[]' is used to dereference and get the value of the adress the pointer is pointing at but it is also used to access array elements and the only reasonable explanation here is that it does both at the same time. Is this how I should think about it?

In the first code snippet, you are initializing an array of pointers with character constants. This results in an integer-to-pointer conversion of those constants. So for example the first element of the array contains the address 97 (assuming ASCII encoding).
When you later attempt to print, you are passing a char * where a char is expected. Using the wrong format specifier triggers undefined behavior. One of the ways that UB can manifest is that things appear to work properly which is the case here.
What probably happened is that pointers and integers get passed to functions in the same manner. And if your system uses little-endian byte representation (which it appears it does), it will end up reading the value used to initialize the array.
Regarding the array index operator [], the expression E1[E2] is exactly the same as *((E1) + (E2)). In the first code snippet array[i] has type char * while in the second code snippet it has type char because that is the type of the respective array elements.

Like already explained by dbush, your first example is wrong.
A more practical use case to demonstrate the pointer part with a string:
#include <stdio.h>
int main(int argc, char** argv) {
char *str = "abc"; //string literal - constant!
printf("%p address of str[0] - str[0] = %c \n", str, *str);
printf("%p address of str[1] - str[1] = %c \n", str+1, *(str+1));
printf("%p addredd of str[2] - str[2] = %c \n", &str[2], str[2]); //alternative notation
return 0;
}
Also there are several similarities between arrays and pointers, for the string example
you can not change the string (the string literal is constant), but you can change the pointer to another string. Other with an array, where you can change the content, but you can not iterate over the array with ++arr, like you can do with the pointer notation, nor can you change the address of arr. Another fact, the array name is the address of the array. And yeah its the same address as the first array element.
With time you will find several useful cases for arrays of pointers, because you already
know, that switching the pointer (the adresses of the object the pointer points to) often provide a more performant method than using the objects themselves...

I would expect that my normal array gives me the values. And the array that holds of pointers gives me the addresse of the values.
You put the same data into each array, so it's not surprising that you got the same data out of them. Specifically:
char *array[] = {'a','b','c','d'};
In this case, you created an array containing four values, and you told the compiler that those values are of type char *. But whatever their type, they're still the same values, 'a', 'b', and so on. You might as well have written:
char *array[] = {97, 98, 99, 100);
because that's exactly the same thing. Specifying the type of the contents of the array as char * doesn't make the compiler treat the values in the array differently -- it doesn't say "oh, I guess in this case I should take the addresses of those values instead of using the values themselves" just because the type is char *. If you want an array of pointers to some set of values, you'll need to get those pointers yourself using other means, such as the & operator, allocating space for each one, etc.
Note: In a comment below, M.M. points out that using values of type char to initialize an array of type char * isn't allowed by the C standard. In my experience, compilers typically warn about this kind of thing (you should've gotten several warnings like warning: incompatible integer to pointer conversion initializing 'char *' with an expression of type 'int' when you compiled your code), but they'll still soldier on and compile the code. In summary: 1) Don't do that, and 2) different compilers may do different things in this situation.
I know that '[]' is used to dereference and get the value of the address the pointer is pointing at but it is also used to access array elements and the only reasonable explanation here is that it does both at the same time.
An array in C is a single contiguous piece of memory in which a number of values, all of the same type and size, are arranged one after another. The [] operator accesses individual values within the array by calculating an offset from the array's base address and using that to get the value. I think the thing that's confusing in your example is that you've created an array of char *, but with values that look like char. As far as the compiler is concerned, though, 'a' (a.k.a. 97, a.k.a. 0x61) is an acceptable value for a pointer to a character, and you could dereference that and get whatever character is stored at location 0x61. (In reality, doing that might cause an exception; the lowest region of memory is reserved on many machines.)

I know that [] is used to dereference and get the value of the adress the pointer is pointing at but it is also used to access array elements and the only reasonable explanation here is that it does both at the same time. Is this how I should think about it?
No. [] is used (in the place you use it) to indicate an array in which the initializer will state the number of elements the array has. Derreferencing a pointer is done with the * left unary operator.
The expression
char *array[] = ...
is used to declare an array of pointers to chars, that will be initialized (normally) with a list of string literals, like these:
char *array[] = { "First string", "Second string", "third string" };
and
char array[] = { 'a', 'b', 'c', 'd' };
making use of the information given above, declares an array of characters with space for four characters, and initialized with array[0] = 'a', array[1] = 'b', array[2] = 'c', array[3] = 'd'.
So the first example will give you an error when trying to initialize an array cell (of pointer to char type) with an integer value (a char is a type of integer) and the second example will compile and execute fine.
The reason you get the same output in both case is unknown(Undefined Behaviour) (well I have some idea) because you have assigned to a pointer variable an integer value (this is probably the thing as the value stored is small enough that can be reinterpreted back without losing information) but the thing is that you have stored the same thing in the array cells, so why do you ask why the output is the same..... what did you expect? You store a char value in a pointer variable and then get it back and print in both samples with exactly the same format specifier, why do you expect (except for conversion errors back to an integer) both codes printing different things? (well, it's undefined behaviour, so you can expect anything and the computer can do otherwise)

There are two compiler warnings you elegantly skip:
warning: initialization of 'char *' from 'int' makes pointer from
integer without a cast [-Wint-conversion]
6 | char *array[] = {'a','b','c','d'};
| ^~~
And the second warning:
warning: format '%c' expects argument of type 'int', but argument 2
has type 'char *' [-Wformat=]
8 | printf("%c\n", array[i]);
| ~^ ~~~~~~~~
| | |
| int char *
| %s
The suggested %s of course would not help. To get valid char-pointers into array[] it would take a "..." string literal, a malloc or a & adress-of on char variable.

Related

if array type does not have = operator then I understand that but why my casting of pointer/array to pointer to array is working not as expected

why this code does not seem to work the way I expect
char *c="hello";
char *x=malloc(sizeof(char)*5+1);
memcpy(x,(char(*)[2])c,sizeof("hello"));
printf("%s\n",x);
On this question I got comment you cannot cast a pointer to an array. But you can cast it to a pointer to array. Try (char*[2])c so I am just casting to pointer to array of two char so it will get first two characters from c becuase this is what (char(*)[2])c suppose to do. If not then am I missing anything? and I thought since Iam copying it the at index after 1 and 2 I get junk because i did not call memset. why I am getting full hello write with memcpy even though I just casted it t0 (char(*)[2])
how to extract specific range of characters from string with casting to array type-- What it can't be done?
Converting a pointer does not change the memory the pointer points to. Converting the c to char [2] or char (*)[2] will not separate two characters from c.
c is char * that points to the first character of "hello".
(char (*)[2]) c says to take that address and convert it to the type “pointer to an array of 2 char”. The result points to the same address as before; it just has a different type. (There are some technical C semantic issues involved in type conversions and aliasing, but I will not discuss those in this answer.)
memcpy(x,(char(*)[2])c,sizeof("hello")); passes that address to memcpy. Due to the declaration of memcpy, that address is automatically converted to const void *. So the type is irrelevant (barring the technical issues mentioned above); whether you pass the original c or the converted (char (*)[2]) c, the result is a const void * to the same address.
sizeof "hello" is 6, because "hello" creates an array that contains six characters, including the terminating null character. So memcpy copies six bytes from "hello" into x.
Then x[5]='\0'; is redundant because the null character is already there.
To copy n characters from position p in a string, use memcpy(x, c + p, n);. In this case, you will need to manually append a null character if it is not included in the n characters. You may also need to guard against going beyond the end of the string pointed to by c.

char * vs char[] and much more

I'm confused about the way C handles strings and char * vs char[].
char name[10] = "asd";
printf("%p\n%p", &name, &name[0]); //0x7ffed617acd
//0x7ffed617acd
If this code gives the same addresses for both arguments, does it mean that the C compiler takes char arrays (strings) as a pointer to the first char in the array and moves in the memory till it gets the null terminator? Why wouldn't the same happen if we changed the char name[] to char *name? (I know they differ but what makes C take both in a different way?)
I know that arrays can't be assigned after declaration (unless you used something like strcpy, strcat) which is also confusing. Why wouldn't C take them as any other data type? (Something tells me the compiler has a specific addr for it while you can assign char* to whatever location in the mem since its a pointer).
I know that char * have fixed size unlike char[] which makes char * not usable for first argument of strcat.
in C a "string" is an array of type "char" (terminated with \0).
When you are referring to an array in C, you are using a pointer to the first element. In this case (char *).
According to the ANSI-C standard the name of an array is a pointer to the first element.
Being able to write name instead of &name[0] is syntactical sugar.
In the same way accessing an array element writing name[i] is analogue to writing *(name+i).
does it mean that the c compiler takes char arrays (strings) as a pointer to the first char in the array
An array is not a pointer. But an array will implicitly convert to a pointer to first element. Such conversion is called "decaying".
... and moves in the memory till it gets the null terminator???
You can write such loop if you know the pointer is to an element of null terminated string. If you write that loop, then the compiler will produce a program that does such thing.
Why wouldn't the same happen if we changed the char name[] to char *name?
Your premise is faulty. You can iterate an array directly, as well as using a pointer.
If this code gives the same addresses for both arguments, does it mean
The address of an object is the first byte of the object. What this "same address" means is that the first byte of the first element of the array is in the same address as the first byte of the array as a whole.
I know that arrays can't be assigned after declaration (unless you used something like strcpy, strcat) which is also confusing.
Neither strcpy nor strcat assign an array. They assign elements of the array which you can also do without calling those functions.
Why wouldn't C take them as any other data type?
This question is unclear. What do you mean by "C taking them"? Why do you think C should take another data type? Which data type do you think it should take?
char name[10] = "asd";
printf("%p\n%p", &name, &name[0]);
The arguments are of type char(*)[10] and char* respectively. The %p format specifier requires that the argument is of type similar to void* which isn't similar to those arguments. Passing an argument of a type other than required by the format specifier results in undefined behaviour. You should cast other pointer types to void* when using %p.

Iterating a pointer vs character array

I am trying to understand a bit more about incrementing arrays vs pointers. For example, the following works:
char string[] = "Hi";
char * pstring = string;
while(*pstring)
printf("%c", *pstring++);
But if I remove the pointer, it will not:
char string[] = "Hi";
while(*string)
printf("%c", *string++);
Why does the first one work? What's the main difference between iteration through a pointer and array?
There's really quite a lot of rationales for why the second one doesn't work. I'm sure you know this, but I'll just reiterate: an array is not a pointer. Arrays are only converted to pointers. This is automatic, and it happens "very often", but arrays and pointers are still different types. In terms of the language, you simply cannot assign to an array (lvalues of array type are not "modifiable lvalues"), and, specifically, the "hidden" string = string + 1 assignment in string++ does not work. You can, of course, assign to a pointer variable. For this reason, in the C standard, ++ is defined to work only on numeric ("real") and pointer types, and this means you aren't allowed to give it an array.
In terms of why the rules are like this, one train of thought starts by noticing that an array type is only "complete" when it has a size—i.e. if you have a variable of array type, its size is a part of its type. Trying to mutate string with arithmetic, as you do here, would require changing the type of string, because the size would change, but this is not allowed in C. (Note that char string[]; is an invalid declaration because it doesn't specify a size; when you added the initializer you told C to infer the size (3) from it.) In the pointer version, pstring is a char*, and so is pstring + 1, so there's no issue. In the array version, you'd need to have char string[3] before the loop and char string[1] afterwards. Worse, the final size of string would depend on the data in it, so there'd be no way to predict it from the language's point of view. Best not open that can of worms, no?
The idea of incrementing string also breaks down because, in C, an "array object" is more than "a bunch of contiguous elements". When you declare string, yes, you create a bunch of char objects that are contiguous in memory, but you also "bless" (this is not a technical term, unless you're using Perl :)) that memory into being a char[3] object. Probably, in terms of the actual machine, this "blessing" doesn't actually do or mean anything, but, in terms of the abstract machine that C programs run on, there is a difference. Specifically, there is neither an char[2] object located at memory address string + 1 nor an char[1] at string + 2. Thus, were you to increment string, there would be no array for string to refer to anymore.
I suppose you can boil all this down to the intuition that an array is really just "a bunch of variables". That is, when you declared char string[3];, that should feel like you did char string_0, string_1, string_2;. This is just like if you had struct { int x; char y; } test;—this feels like writing int test_x; char test_y;. "Incrementing a group of variables" is quite meaningless, so of course string++ and test++ are disallowed. With string, you have the option to create a char *pstring, such that pstring = &string_0, pstring + 1 = &string_1, pstring + 2 = &string_2, but that doesn't change the fact that doing arithmetic on string itself (especially destructively incrementing it) doesn't make sense.
Here's my two bits....
Why does the first one work?
The pointer "pstring" is a 'variable'. This means that the pointer "pstring" can be re-assigned a new value.
pstring++ is "pstring = pstring + 1" (allowed).
Other valid pointer operations are:
Assignment of pointers of the same type.
Adding or Subtracting a pointer and an integer.
Subtracting or Comparing two pointers to members of the same array.
Assigning or Comparing a pointer to zero(NULL).
What's the main difference between iteration through a pointer and array?
The name of the array(synonymous with the location of the first element) is not a "variable" and will always refer to the same storage.
Though an integer can be added to or subtracted from an array name, re-assigning a new value to an array name is illegal.
string++ is "string = string + 1" (not allowed).
The difference in coding is extrapolated further in the following:
char string[] = "Hi";
int i = 0;
while(*(string+i)){ // or string[i]
printf("%c", *(string+i));// or string[i]
i++;
}

Type of a pointer?

There are countless questions about pointers here on SO, and countless resources on the internet, but I still haven't been able to understand this.
This answer quotes A Tutorial on Pointers and Arrays in C: Chapter 3 - Pointers and Strings:
int puts(const char *s);
For the moment, ignore the const. The parameter passed to puts() is a pointer, that is the value of a pointer (since all parameters in C are passed by value), and the value of a pointer is the address to which it points, or, simply, an address. Thus when we write puts(strA); as we have seen, we are passing the address of strA[0].
I don't understand this, at all.
Why does puts() need a pointer to a string constant? puts() doesn't modify and return its argument, just writes it to stdout, and then the string is discarded.
Ignoring the why, how is it that puts()'s prototype, which explicity takes a pointer to a string constant, accepts a string literal, not a pointer to one? That is, why does puts("hello world"); work when puts()'s prototype would indicate that puts() needs something more like char hello[] = "hello world"; puts(&hello);?
If you give, for instance, printf() a pointer to a string constant, which is apparently what it wants, GCC will complain and your program will segfault, because:
error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[6]’
But giving printf() a string constant, not a pointer to a string, works fine.
This Programmers.SE question's answers make a lot of sense to me.
Going off that question's answers, pointers are just numbers which represent a position in memory. Numbers for memory addresses are unsigned ints, and C is written in (native) C and assembly, so pointers are simply architecture-defined uints.
But this is not the case, since the compiler is very clear in its errors about how int, int * and int ** are not the same. They are a pathway that eventually points to something in memory.
Why do functions that need a pointer accept something which is not a pointer, and reject a pointer?
I'm aware a "string constant" is actually an array of characters but I'm trying to simplify here.
The expression "hello world" has type char[12].
In most contexts, use of an array is converted to a pointer to its first element: in the case of "hello world" it is converted to a pointer to the 'h', of type char*.
When using puts("Hello world"), the array is converted to char*.
Note that the conversion from array of specific size, loses the size information.
char array[42];
printf("size of array is %d\n", (int)sizeof array);
printf("size of pointer is %d\n", (int)sizeof &array[0]);
puts() doesn't need a pointer to a string, it needs a pointer (*) to a character (char). It happens that in C, a pointer to a character (char *) can be assimilated to a string (an array of chars), provided that the end of the string is a null character \0.
Why does puts() need a pointer to a string constant? puts() doesn't modify and return its argument, just writes it to stdout, and then the string is discarded.
puts receives a pointer to the first character in a string; it will then "walk" down that string until it sees a 0 terminator. A naive implementation would look something like this:
void puts( const char *ptr )
{
while ( *ptr ) // loop until we see a 0-valued byte
putchar( *ptr++ ); // write the current character, advance the pointer
// to point to the next character in the string.
putchar( '\n' );
}
Ignoring the why, how is it that puts()'s prototype, which explicity takes a pointer to a string constant, accepts a string literal, not a pointer to one? That is, why does puts("hello world"); work when puts()'s prototype would indicate that puts() needs something more like char hello[] = "hello world"; puts(&hello);?
Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
String literals are stored as arrays of char (const char in C++); thus, the string literal "hello world" is an expression of type "12-element array of char". When you call puts( "hello world" );, the string literal is not the operand of the sizeof or unary & operators, so the type of the expression is converted to "pointer to char", and the value of the expression is the address of the first character in the string.
If you give, for instance, printf() a pointer to a string constant, which is apparently what it wants, GCC will complain and your program will segfault, because:
error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[6]’
Remember above where I said an array expression is converted to a pointer type except when it is the operand of the sizeof or unary & operators or used to initialize another array in a declaration. Assume the declaration
char hello[] = "hello world";
Like above, the expression "hello world" has type 12-element array of char; however, because it is being used to initialize another array of char in a declaration, it is not converted to a pointer expression; instead, the contents of the string literal are copied to the hello array.
Similarly, if you call printf as follows:
printf( "%s", &hello );
then the expression hello is not converted to a pointer to char; instead, the type of the expression &hello is "pointer to 12-element array of char", or char (*)[12]. Since the %s conversion specifier expects a char *, you should just pass the array expression as
printf( "%s", hello );
and with string literals, just use the literal:
printf( "%s", "hello world" );
Going off that question's answers, pointers are just numbers which represent a position in memory. Numbers for memory addresses are unsigned ints, and C is written in (native) C and assembly, so pointers are simply architecture-defined uints.
But this is not the case, since the compiler is very clear in its errors about how int, int * and int ** are not the same. They are a pathway that eventually points to something in memory.
C is a (more or less) strongly-typed language; types matter. Even though an int, int *, and int ** may take up the same amount of space in memory1, semantically they are very different things and are (usually) not interchangable. A pointer to an int is a distinct type from a pointer to float, which is a distinct type from a pointer to an array of char, etc. This matters for things like pointer arithmetic; when you write
T *p = some_address();
p++;
The expression p++ advances p to point to the next object of type T. If sizeof (T) is 1, then p++ advances a single byte; if sizeof (T) is 4, then p++ advances 4 bytes (assuming a byte-addressed architecture, which most of us work on).
1. Or not. There is no guarantee that pointers to different types have the same size or representation as each other, nor is it guaranteed that they're just unsigned integers; on a segmented architecture, they may have a more complicated page:offset representation.
Several questions in there, but hopefully I can illustrate how pointers to pointers work.
The reason puts need a pointer, is that C really does not have a built in type for a string. A string is just a bunch of char one after another. Hence, puts needs a pointer to the first of the chars.
The string literal, "degrades gracefully" to a pointer. This is fancy compiler speak meaning that a string literal actually is a string of chars and is represented by a pointer to the first of the chars.
You need a pointer to a pointer to a type, for instance, if you want to "return" an array from a function, like so:
bool magic_super_function(int frob, int niz, char** imageptr /* pointer to pointer */)
{
char* img = malloc(frob * niz * IMAGE_DEPTH);
if (NULL == ptr) {
return false;
}
*imageptr = img;
return true;
}
Sometimes an example (even contrived) can illustrate a point. You would call
this function like so:
char* img; /* pointer to char */
if (true == magic_super_function(12, 8, &img /* pointer to pointer (to char)*/ )) {
/* Here img is valid and allocated */
/* Do something with img */
} else {
/* img has no valid value here. Do not use it. */
/* Something failed */
}
An int is different from int* because of how it will be used in the code. You can expect to access the memory location that int* points to and find an integer value. This is called 'strong typing' and the language does this so that there are strict rules for how you use your variables. So even though an int and int* might both be the same size, an int cannot be used as a pointer. Similarly an int** is a pointer to a pointer, so would have to be dereferenced twice to find the actual integer value it refers to.
In the example of puts(const char*) the definition of the function tells you that the function expects a memory location (pointer) to a null-terminated set of char values. When doing the operation, puts will dereference the location you give it, and print the characters found there. The const part tells you it won't be changing the values either so that it's safe to send a const array of char to it. When you send a literal string like puts("hello"), the compiler turns that into a pointer to "hello" for you as a convenience, so a pointer is still sent (not a copy of the string).
Regarding your question about printf, note that char* and char*[6] are different. The first indicates a pointer to a null-terminated string, where the second is a pointer to a set of exactly six char values which may not be null-terminated. The compiler complains because if puts(&hello) tried to treat the input parameter as a null-terminated string, it would not stop after then length of the array, and would access memory that it should not.
int **r = 90; r is a double pointer and you are assigning 90 to the pointer. When you dereference, it will try to dereference address 0x90.
Why does puts() need a pointer to a string constant?
puts() is defined in such a way so that it can make use of the actual parameter instead of copying it and reusing it. Because it improves performance. Moreover it takes a const pointer so it can't change the content pointed by the pointer. It is call by reference.
How is it that puts()'s prototype, which explicitly takes a pointer to
a string constant, accepts a string literal, not a pointer to one?
When you pass a string literal, first the string literal is stored in read only memory and then a pointer to that memory is actually passed. So you can call puts() with any literal like puts("abcd"), puts("xyz"). It will work.
error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[6]’
Here your are actually passing a pointer to an array of 6 chars not a char *. So the compiler will complain this error.

Arrays of strings in C

I need to hold an array of C strings. Now I know C strings are just an array of chars so essentially what I want is a 2d array of chars. The strings I'm trying to store will also never exceed 6 characters. My plan is to initialize a char array with 50 "string slots" and then if I hit 50 strings reallocate the array's memory to double it's capacity. I've tried something simple like:
int main() {
char strings[50][6];
strings[0] = "test";
printf("The string is: %s", strings[0]);
return(0);
}
But, when I go to compile it I get the following error:
test.c: In function ‘main’: test.c:3:
error: incompatible types when
assigning to type ‘char[6]’ from type
‘char *’ test.c:4: warning:
incompatible implicit declaration of
built-in function ‘printf’
Can anyone point in me in the right direction?
strncpy(strings[0], "test", 6); unless your C library has strlcpy(). However if you are going to need to vary the size of the storage, you're better off using a char ** with malloc(), realloc() and free().
One can't assign arrays directly in that way. In your current case, you would need to do something like...
strcpy (strings[0], "test");
It would be more idiomatic to use an array of pointers, though. Have a look at p111 and onwards of K & R.
Use strncpy (if at all possible) or strcpy for your assignment.
First the easy part. You do need to
#include <stdio.h>
to get rid of the incompatible printf warning. This has to do with the way the standard says C works, which is to allow you to make some function that is unlike the standard printf, the implicit declaration of that function with its signature (incorrectly) guessed by the compiler, and the compiler knowing that while you can define a different printf you probably didn't actually mean to.
Ok, now the more complicated part. Arrays in C are a little special. The can evaluate to pointer literals (which can't be assigned to, which is similar to trying to 6 = 4;), or they can evaluate to an entire array, depending on context. Usually they are pointer literals, but in this case strings[0] is seen as an array, which is why you get the error you got rather than one stating that strings[0] was an invalid l-value (left-value, meaning something that can be on the left side of a =). Either way you can't copy a character pointer literal (which is what "test" evaluates to) to an array. When you do this on the line where you declare a string (char array) the compiler treats it differently, though, which can cause some confusion. Anyway, you need to either use strcpy to copy the characters that make up "test" or initialize strings[0] to "test" like this:
char strings[50][6] = { "test" }; // only initializes the first member of the array
You can't assign array contents using the = operator. First of all, an array object cannot be a target of the assignment operator (Online C Standard, draft n1256, section 6.5.16.1, paragraph 1). strings[0] is an array object of type char [6], so it can't appear on the LHS of the = operator.
Second of all, when an array expression is not an operand of either the sizeof or address-of & operators and is not a string literal being used to initialize the contents of another array, the type of the expression is implicitly converted ("decays") from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array (section 6.3.2.1, paragraph 3).
The string literal "test" is a 5-element array of char (const char in C++) with static extent (meaning the memory for it is allocated at program startup and held until the program exits). However, when it appears in the expression
strings[0] = "test";
its type is converted from "5-element array of char" to "pointer to char" and its value is the address of the first element, so what you wind up doing is attempting to assign a pointer value to an array object, which is not a compatible type; bad juju, over and above not being able to assign an array object anyway.
If you want to copy the contents of one array to another, then you will need to either assign each array element individually, such as
strings[0][0] = 't';
strings[0][1] = 'e';
strings[0][2] = 's';
strings[0][3] = 't';
strings[0][4] = 0;
or even
size_t len = strlen("test");
size_t i;
for (i = 0; i < sizeof strings[0] - 1 && i < len; i++)
strings[0][i] = "test"[i]; // yes, you can subscript a string literal
strings[0][i] = 0;
or use a library function like memcpy(), strcpy(), strncpy(), strcat(), sprintf(), etc.:
strcpy(strings[0], "test");
or
strncpy(strings[0], "test", sizeof strings[0] - 1); // -1 to leave room
// for 0 terminator
// if necessary
or
sprintf(strings[0], "%*s", (int) sizeof strings[0] - 1, "test");
Note that you can initialize the array's contents when you declare it, like so:
char foo[] = "test"; // foo is implicitly sized to 5 (+1 for 0 terminator)
int bar[] = {1,2,3,4,5}; // again, size is implied from initializer
float f[3] = {1.0, 2.0, 3.0}; // Initializer cannot contain more items than
// array is sized for
I see there's a merry war over the use of strcpy() vs. strncpy() in the comments to another answer; my position is to use whichever one is appropriate to the given situation. If you know that your buffers are big enough to handle the largest possible input, use strcpy(). If not, use strncpy(), but be aware that you may have to add the 0 terminator manually.
The problem you have is in the way that the compiler interprets the statement char strings[50][6];
Instead of what you hoped, a char array with 50 slots for 6 char strings, you got a char array of single chars with dimesions 50x6.
Rather than char strings[50][6];, the way you want to initialise your array is as follows (I only know how to do this on the heap, sorry):
char ** strings[50] = malloc(50 * sizeof(char *));
for(int i = 0; i < 50; ++i)
{
strings[i] = malloc(50 * 6 * sizeof(char *));
}
Don't forget to clean with frees afterwards.
EDIT: And as said above. Before your main method. Inlcude the line #include <stdio.h>. This is where the printf() function is located.

Resources