These are the notations used for 2D Arrays
char (*names)[5] ;
and
char* names[] = {"Jan","Feb"};
and
char names[3][5] = { Initializers..};
I'm getting extremely confused between these notations.
The 1st one declares names to be a pointer to an array of 5 chars i.e
names -> a char pointer -> "Some string"
The 3rd one has a different memory map, i.e it is stored in row major order like a normal array unlike the one stated above.
How is the 2nd notation similar or different from the 1st and 3rd notation.?
Also passing them to functions is a different story altogether. If we declare the 2d array to be of type 2, then it is passed as a double pointer (char** names) while if it is of type 1 or type 3, the columns should be mentioned in the declaration.
Please help me attain more clarity over these issues.
Thanks.
Only one of those examples is a 2D array:
char names[3][5];
The others are different:
char (*names)[5] ;
is a pointer to a 1D array, and:
char* names[] = {"Jan","Feb"};
is a 1D array of pointers.
I'm going to rename them now to be clearer:
char a[3][5];
char (*b)[5];
char *c[3];
a is the only real two dimensional array. That is, it occupies contiguous memory and has room for three strings, each 5 characters long (including null terminator).
b is a pointer to an array; no storage for any potential contents of that array is included.
c is an array of pointers, each can be used to point to any string you happen to care about; no storage is reserved for any of the strings themselves, just for the three pointers.
If you have a function with a prototype like:
void myfunction(char **p);
Only c can be passed to this function; the others won't behave the way you'd like them to.
Related
would someone please explain the difference between
char *names[3]
and
char (*names)[3]
and how to read this operators?
If I want to allocate memory for them dynamically how to do so?
For the first case, I think it's just an array of char* of length 3, so no memory allocation not applicable. But in second case how to do memory allocation?
When faced with questions like this, you can usually turn to cdecl (online version here):
cdecl> explain char *names[3]
declare names as array 3 of pointer to char
cdecl> explain char (*names)[3]
declare names as pointer to array 3 of char
So the former creates array of three pointers-to-char:
+----------+
| names[0] | -> char
| [1] | -> char
| [2] | -> char
+----------+
And the latter creates a single pointer to a char array of size three.
+-------+
| names | -> char, char, char - no, not a dance step :-)
+-------+
The second line decodes as "declare names as pointer to array 3 of char".
I've been writing C for over 25 years, and I've never used such a variable.
Anyway, I guess this should work:
char data[3];
char (*names) = data;
Note that the variable name, names, is highly misleading since the variable holds only 3 single characters, as opposed to char *names[3] which is three pointers to characters and thus easily could be used to hold three strings.
Also note that the above code makes little sense, you could just use data directly if you had it.
The first an array of three pointers to char.
The second is a pointer to an array of three chars.
(Read it as "*names is a char[3]").
You can create such a pointer by taking the address of an array of three chars:
char name[3];
char (*names)[3] = &name;
or dynamically in the normal way:
char (*names)[3] = malloc(sizeof(*names)); /* or sizeof(char[3]), if you're fond of bugs */
or through the regular array-to-pointer conversion:
char stuff[2][3] = {};
char (*names)[3] = stuff; /* Same as &stuff[0], as normal. */
and how to read this operators?
Let's take the second one as it is the more complex of the two:
char (*names)[3];
When you are looking at a complex definition like this, the best way to attack it is to start in the middle and work your way out. “Starting in the middle” means starting at the variable name, which is names.
“Working your way out” means looking to the right for the nearest item (nothing in this case; the right parenthesis stops you short), then looking to the left (a pointer denoted by the asterisk), then looking to the right (an array of 3), then looking to the left (char).
This right-left-right motion works with most declarations.
This means names is a pointer to an char array of size 3.
This is very strange declaration but that is how it is read.
If I want to allocate memory for them dynamically how to do so?
Now that you know what the declaration means, memory allocation becomes easy:
char (*names)[3] = malloc(3 * sizeof(char));
char *names[3] is an array of 3 char pointers.
char (*names)[3] is an array pointer (pointer to array) to an array of 3 characters char[3].
So these two have fundamentally different meanings! Don't confuse them with each other.
If you wish to allocate an array of pointers, then you can do it as in either of these examples:
char** names = malloc(3 * sizeof(*names) );
char** names = malloc(sizeof(char*[3]));
char** names = calloc(3, sizeof(char*));
These are all equivalent (but calloc also sets all pointers to NULL). names will be a pointer to the first element in the array. It will be a pointer to a char*.
If you wish to allocate an array and point to the first element, simply do:
char* names = malloc(3 * sizeof(*names));
Alternatively, you can use the array pointer syntax and point to the array as whole:
char (*names)[3] = malloc(sizeof(*names));
In terms of one dimensional array, its array name is also the address of the first element. So it is fine to assign it to a pointer, like below:
char data[5];
char* p_data=data;
So I think it should be the same with two dimensional array. The array name should be the address of the first element's address. So, I'd like to do something like this:
char data[5][5];
char** pp_data=data;
Then I get a warning saying the pointer type char** is incompatible with char[ ][ ].
Why does this happen? Do I comprehend the pointer and array concept wrong?
You're right that an array is often referred to by a pointer to its first element. But when you have the "two dimensional" array
char data[5][5];
what you actually have is an array of arrays. The first element of the array data is an array of 5 characters. So this code would work:
char (*pa_data)[5] = data;
Here pa_data is a pointer to array. The compiler won't complain about it, but it may or may not actually be useful to you.
It's true that a pointer-to-pointer like your char **pp_data can be made to act like a two-dimensional array, but you have to do some memory allocation for it to work. It turns out that in the array-of-arrays char data[5][5] there's no pointer-to-char for pp_data to be a pointer to. (In particular, you could not say something like pp_data = &data[0][0].)
See also this question in the C FAQ list.
Two dimensional array is actually an array of arrays. It means the first element of that array is an array. Therefore a two dimensional array will be converted to pointer to an array (its first element).
In
char data[5][5];
when used in expression, wit some exception, data will be converted to pointer to its first element data[0].data[0] is an array of char. Therefore the type of data will become pointer to an array of 5 char, i.e. char (*)[5].
char ** and char (*)[5] are of different type, i.e. incompatible type.
Consider the following declaration:
char *name[]={"John","Beckham"};
Is this considered as 2D Array or not?
Because my professor told me that it's not 2D array but something else,
and if yes ..we can say that we can declare 2D array without specifying dimensions.
It is an array of char*. It's length is 2. The first element is a pointer which points to the string literal "John", and the second is a pointer which points to the string literal "Beckham".
The entire structure is two-dimensional, in the sense that two numbers specify the location of one of the char elements (for example, the character 'k' is located at (1,3)). But it is not rectangular, so it does not have a simple size like [2, 7] (since there is no (0,4) element). It is not what people usually refer to when they talk about a "two-dimensional array".
Of course your professor is right. An array named Arr of type T might look like
T Arr [] = { ... };
In this case, T is the type char *, and the brackets [] denote an array of char *s.
The difference relies on the fact that a pointer is not an array.
See the C FAQ for information on the differences.
This question already has answers here:
C pointer to array/array of pointers disambiguation
(13 answers)
what is difference between defining char a[5] and char (*a)[5]? [duplicate]
(4 answers)
Closed 8 years ago.
When I read books about C language, the two level pointer bothered me a lot.
char s[5][5];
char *s[5];
char (*s)[5];
so what is the difference between them?
In C, it is better to speak out the declaration. Then, it becomes intuitive. For this, you follow the right-left convention. Here is how it goes:
char *s[5];
How do you speak it? For that you start at the right of the variable name s and then go to the left. So you start by saying "s is a/an", On the right, you see a [] and you say "s is an array ... ". And then you go to the left and see the *, and say "s is an array of pointers." And that is what it is. It si an array of 5 pointers. You can store different pointers in this array.
Now for the other one:
char (*s)[5];
You start the same way. "s is a/an", and then look at the (). Anything within the () is bound to s closer than anything outside. So the * is more closely bound with s than []. So You now say, "s is a pointer ..." and now you go out of the parenthesis and see the []. So you continue, "s is a pointer to an array". And that is exactly what it is. It is a pointer, which will point to the first element of an array.
Now follow the same logic and try to guess what the following will be:
int (*callme)(int a, int b)
int (*callme[10])(int a, int b)
Hint, the last one can be used to create lookup tables for functions.
Edit:
As mentioned in the comments, there is also a char in the beginning. I have never ben able to figure out an easy way of speaking this, but is generally clear from the context. For example, in the first example, the char defines the type of the array, while in the second example, it defines pointer. In the exercises I have posted, the int defines the type for the return values of the functions. Generally with definitions such as these, there will be exactly one item with the undefined type. And thats how I figure out where the type goes.
first is 2 dimensional array of char
second is array of pointer to char
third is pointer to an array of char
While declaration was covered, perhaps differences in usage should also be pointed out:
char s[5][5]; --
s points to an area of allocated memory (heap if global, stack if local),
you may safely write up to 25 char values at s[0][0] .. s[4][4] (or at s[0] .. s[24]),
sizeof(s) == 25.
char *s[5]; --
s points to an area of allocated memory (heap if global, stack if local),
you may safely write up to 5 pointer values at s[0] .. s[4],
sizeof(s) == 40 (*).
char (*s)[5]; --
s does not point to any allocated memory -- it's merely an uninitialized pointer at this point,
you may safely write one pointer value at &s,
sizeof(s) == 8 (*).
(*) note: assuming a 64-bit architecture.
1.char s[5][5];
Here s is two dimensional array with 5 rows and 5 columns. Where in this 5 rows and 5 columns you will save element of type character.
2.char *s[5];
s is a one dimensional array with 5 elements each element is of type pointer to character.
3.char (*s)[5];
s is a pointer here not array. S points to a array of characters. for eg.
char arr[5][5];
char(*s)[5];
s = arr;
s[0][0] will be same as array of arr[0][0]
I am trying to pass an array of character strings (C style strings) to a function. However, I don't want to place a maximum size on length of each string coming into the function, nor do I want to allocate the arrays dynamically. Here is the code I wrote first:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void fun(char *s[])
{
printf("Entering Fun\n");
printf("s[1]=%s\n",(char *)s[1]);
}
int main(void)
{
char myStrings[2][12];
strcpy(myStrings[0],"7/2/2010");
strcpy(myStrings[1],"hello");
fun(myStrings);
return(0);
}
I got a seg fault when run and the following warning from the compiler:
stackov.c: In function ‘main’:
stackov.c:17: warning: passing argument 1 of ‘fun’ from incompatible pointer type
stackov.c:5: note: expected ‘char **’ but argument is of type ‘char (*)[12]’
However, when I change the main() to the following it works:
int main(void)
{
char myStrings[2][12];
char *newStrings[2];
strcpy(myStrings[0],"7/2/2010");
strcpy(myStrings[1],"hello");
newStrings[0]=myStrings[0];
newStrings[1]=myStrings[1];
fun(newStrings);
return(0);
}
Isn't array[2][12] the same thing as an array of character pointers when it is passed to a function?
No, char array[2][12] is a two-dimensional array (array of arrays). char *array[2] is an array of pointers.
char array[2][12] looks like:
7/2/2010\0\x\x\xhello\0\x\x\x\x\x\x
where \0 is NUL and \x is indeterminate.
while
char *array[2] is:
0x CAFEBABEDEADBEEF
(assuming 32-bit)
The first has 24 contiguous characters, the second has two pointers (to the beginnings of strings elsewhere).
Try
void fun(char s[][12]) { ...}
Read also from the c-faq: My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer
Isn't array[2][12] the same thing as an array of character pointers when it is passed to a function?
No, it is a two-dimensional array. The difference is that an array of pointers contains pointers, but array[2][12] is actually an array of arrays - no pointers involved.
BTW you could do:
char* mystrings[2]={"aha", "haha"};
fun(mystrings);
char myStrings[2][12]; declares myStrings as an array of arrays of characters. This means that myStrings is stored as the 24 bytes
7/2/2010.???hello.??????
‘——————————’‘——————————’
myStrings[0]myStrings[1]
where . represents a null character and ? represents an uninitialized byte.
char *newStrings[2]; declares newStrings as an array of pointers to characters. This means that newStrings is stored as the 2×sizeof(char*) bytes
[..][..]
where [..] represents a pointer object (not yet initialized).
If you want to pass strings of different lengths to your function, you have to pass an array of pointers, not an array of arrays. As you can see above, these are different layouts.
General advice: whenever you're around pointers, draw diagrams (on whiteboard or blackboard if you can, otherwise on paper) showing the various objects in memory, with arrows indicating what is pointing where. There are two kinds of C programmers: the ones who draw such diagrams when they encounter pointers, and the really experienced ones who draw the diagrams in their head.
Your array is declared as a 2-D array, but you want to pass it to the function as though it's a 1-D array of string pointers.
Tom's answer is correct, you can omit the size of the first dimension of multidimensional array declarations for function parameters.
Your second solution works because it explicitly passes a 1-D array of string pointers to the function. Of course, it requires the extra overhead of the array of pointers in addition to the original 2-D string array.