What is the difference between char *s[] and char (*s)[]? [duplicate] - c

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]

Related

What is the difference between this two declarations " int **matrix " and " int matrix [] [] "? [duplicate]

This question already has answers here:
Is 2d array a double pointer? [duplicate]
(4 answers)
Closed 8 years ago.
What I learnt from C language is that
int **matrix = matrix is a pointer to pointer to int
when we want to create a matrix we will malloc a set of contigus pointers !
so here is the first pointer pointing to 1 pointer to an int or it can point to a set of pointers which are pointing to an int ( the first pointer will of course point to the address of the first pointer )
Brievely pointing to 1 pointer (only one ) is it the same as pointing to first pointer from a set of pointers ?
I think the answer resides inside this question What is exactly an array of something ?
Pointers and arrays are fundamentally different, especially wrt. to their behavior with sizeof() and wrt. what they allocate. However, they can sometimes be used interchangeably, because both essentially represent an address.
If you dynamically allocate memory, you will receive a pointer, which points to the beginning of a chunk of memory. If you allocate memory of a size that represents a multiple of a type's size, it should be intuitively clear that you can store as many elements of one type there, as you have allocated space for. Since C pointer arithmetic interprets *(p + n) - which is the same as p[n] and n[p] - as an access to the address of p plus n times the size of an element of the type p points to, it should now be easier to understand that you can interpret the pointer as the beginning of an array.
For your case, that means you can interpret int **p as a pointer to an int-pointer. Past the memory of this pointer, n more int pointers may follow, while every one of these pointers represents the address of an int, past which, once again, n more ints may follow. Thus, even though int **p is actually a pointer to a pointer of type int, it is possible to interpret it as two-dimensional array. How many elements past your pointer belong to the array is something that you cannot know from neither an array not a pointer, which is why you will usually have a n_size and/or m_size argument or something similar.
In the beginning I said that you can "sometimes" treat them as the same. To make this explicit, you can use pointers and arrays interchangeably in these cases:
When passed to a function a type[] "decays" to a type * e.g. f(type *a)
If accessing elements with the [] operator, a[i] always resolves to *(a + i)
When they occur in an expression, e.g. ++a
cf: van der Linden - Deep C
if you want a quick answer try making this tiny program
#include <stdio.h>
#include <stdlib.h>
int main()
{
int matrix[2][3];
int **m;
m=malloc(sizeof(int *)*2);
m[0]=malloc(sizeof(int)*3);
m[1]=malloc(sizeof(int)*3);
m=matrix;
return 0;
}
The compiler will answer you that the two declarations are different. In fact:

Why is char*p[10] considered char** p by the compiler? [duplicate]

This question already has answers here:
Should I use char** argv or char* argv[]?
(10 answers)
Closed 8 years ago.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function (see my other question here: Why is this array size "workaround" giving me a warning?), but my question is more about a warning that gcc is giving that doesn't make sense to me.
According to this website (EDIT: I misread the website), char *p[10] declares a pointer to a 10-wide array of chars. But when I tried to pass in a pointer to an array into a function, I got this error message from the compiler:
Here is the rest of the program:
I know that when an array is passed into a function, it decays into a pointer (losing information about its length), but it seems that the declaration itself is decaying. What's going on here?
EDIT: When I replace the char *p[10] with char (*p)[10], it doesn't give the warning anymore, and more importantly, it displays the proper array length: 10. I guess my questions are 1) Why do the parentheses change things? and 2) Is this a well-known workaround or am I relying on some behavior of the compiler that isn't guaranteed? (i.e. that array length info can be passed by indirectly passing in a pointer to it?)
In fact char *p[10] is an array, of length 10, of pointers to char. You are looking for char (*p)[10]. That is a pointer to an array, of length 10, of char.
You might find http://cdecl.org/ a useful resource to help you test your understanding of declarations.
Regarding the discussion surrounding dynamic arrays, you are going to have to accept that once you allocate an array dynamically, the system provides no means for you to recover the length of the array. It is your responsibility to remember that information.
The subject of your question has been answered already but I wanted to address the heart of it, which is "can I encode the length of an array in its type?" Which is in fact what a pointer-to-array does. The real question is whether you can actually gain any brevity or safety from this. Consider that in each scope where you have a declaration of your type, the length still needs to be known a-priori. To show you what I mean let's generalize your example slightly by making 10 a compile-time constant N.
#define N 10
size_t arraylength(char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
char array[N];
assert( arraylength(&array) == N ); //always true
}
So far so good. We didn't have to pass the length of array anywhere. But it's easy to see that anywhere the expression sizeof(*arrayp) is used, we also could have written N. And any place we declare a char(*)[ ], the bracketed length must come from somewhere.
So what if N isn't a compile time constant, and array is either a VLA or a pointer-to-array from malloc? We can still write and call arraysize, but it looks like this:
size_t arraylength(size_t N, char (*arrayp)[N]) {
return sizeof(*arrayp);
}
int main(void) {
size_t N = length_from_somewhere();
char array[N];
assert( arraylength(sizeof(array), &array) == N );
}
In defining arraysize N must still be visible before the declaration of arrayp. In either case, we can't avoid having N visible outside of the declaration of arrayp. In fact, we didn't gain anything over writing arraysize(size_t N, char* array) and passing array directly (which is a bit silly given the purpose of this function.) Both times arraylength could have equally been written return N;
Which isn't to say that array pointers are useless as parameters to functions -- in the opposite situation, when you want to enforce a length, they can provide type checking to make sure somefunc(char (*)[10]); receives a pointer to an array that is really (sans shady casting) 10 elements long, which is stronger than what a construct like [static 10] provides.
Also keep in mind that all of the length measurements above depend on the underlying type being char where length == size. For any larger type, taking the length requires the usual arithmetic e.g.
sizeof(*arrayp)/sizeof((*arrayp)[0])
In C, arrays decay to pointers to their first elements on most uses. In particular, what a function receives is always just a pointer to the first element, the size of the array is not passed with it.
Get a good text on C and read up on arrays.
I've been fiddling around to see if there's any way to retain information about an array's length automatically when passed into a function
The problem is so annoying that lots of programmers would love to have an answer. Unfortunately, this is not possible.
It seems that the declaration itself is decaying
Pointer to an array is not the same as a pointer to a pointer; that is why you are getting an error.
There is no decaying going on in your code, because you are not passing an array in your code sample: instead, you are trying to pass a pointer to an array &p. The pointer to an array of characters is not compatible to the expected type of the function, which is char**. Array size from the declaration is ignored.
You need to keep in mind two things:
1. Arrays are not pointers.
2. Array names decays to pointers (in most cases) when passed as arguments to functions.
So, when you declare
int a[10]; // a is an array of 10 ints
int *b; // b is a pointer to int
both of a and b are of different types. Former is of type int [10] while latter is of type int *.
In case of function parameter
void foo1 (int a[10]); // Actually you are not passing entire array
void foo2 (int a[]); // And that's why you can omit the first dimension.
void foo3 (int *a); // and the compiler interprets the above two third
ain all of the above function declarations is of same data type int *.
Now in your case
unsigned long arraySize(char *p[10]);
you can declare it as
unsigned long arraySize(char *p[]);
and hence
unsigned long arraySize(char **p);
All are equivalent.
char *p[10] char *p[] and char **p all are exactly equivalent but when they are declared as parameter of a function otherwise char *p[10] (an array of 10 pointers to char) and char **p (a pointer to pointer to char)are entirely of different type.
Suggested reading: C-FAQ: 6. Arrays and Pointers explains this in detailed.
Array name itself is a constant pointer. for example int arr[10]={0};
arr contains the address of arr[0]. hence arr equals&arr[0] .
when u pass the arraysize(&p) , you are actually passing a double pointer .
The correct format to pass a array pointer would be arraysize(&p[0]) or arraysizeof(p)
Note Array name is constant pointer , you cant change its value .
int arr[10];
arr++;
is invalid.
In your case you cant find a size of an array in function by passing the array name . it would return size of pointer(4 or 8 depends on your processor .
The method is to pass the size along with the array
func(array_name , array_size);

Different pointer notations in 2D Arrays?

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.

Why can't I treat an array like a pointer in C?

I see this question a lot on SO. Maybe not in so many words... but time and again there is confusion on how arrays are different from pointers. So I thought I would take a moment to Q&A a few points about this.
For purposes of this Q&A we're going to assume a 32-bit system and the following have been declared:
char * ptr = "hello";
char arr[10] = "hello";
int iarr[10] = {0};
Here's a list of questions that surmise the confusion I see on SO. As I see new ones I'll add to my list of Q&A (others feel free to as well, and correct me if you see any mistakes!)
Isn't a pointer and an array basically the same thing?
Follow up: both *(ptr) and *(arr), or ptr[0] and arr[0] give the same thing, why?
How come arr and &arr is the same value?
Follow up: why do I get a different value printing arr+1 vs &arr+1?
1) Pointers are not arrays. Arrays are not pointers. Don't think of them that way because they are different.
How can I prove this? Think about what they look like in memory:
Our array arr is 10 characters long. It contains "Hello", but wait, that's not all! Because we have a statically declared array longer than our message, we get a bunch of NULL characters ('\0') thrown in for free! Also, note how the name arr is conceptually attached to the contiguous characters, (it's not pointing to anything).
Next consider how our pointer would look in memory:
Note here we're pointing to a character array some place in read only memory.
So while both arr and ptr were initialized the same way, the contents/location of each is actually different.
This is the key point:ptr is a variable, we can point it to anything, arr is a constant, it will always refer to this block of 10 characters.
2) The [] is an "add and deference" operator that can be used on an address. Meaning that arr[0] is the same as saying *(arr+0). So yes doing this:
printf("%c %c", *(arr+1), *(ptr+1));
Would give you an output of "e e". It's not because arrays are pointers, it's because the name of an array arr and a pointer ptr both happen to give you an address.
Key point to #2: The deference operator * and the add and deference operator [] are not specific to pointers and arrays respectively. These operators simply work on addresses.
3) I don't have an extremely simple answer... so let's forget our character arrays for a second and take a look at it this example for an explanation:
int b; //this is integer type
&b; //this is the address of the int b, right?
int c[]; //this is the array of ints
&c; //this would be the address of the array, right?
So that's pretty understandable how about this:
*c; //that's the first element in the array
What does that line of code tell you? If I deference c, then I get an int. That means just plain c is an address. Since it's the start of the array it's the address of the array and also the address of the first element in the array, thus from a value standpoint:
c == &c;
4) Let me go off topic for a second here... this last question is part of the confusion of address arithmetic. I saw a question on SO at one point implying that addresses are just integer values... You need to understand that in C addresses have knowledge of type. That is to say:
iarr+1; //We added 1 to the address, so we moved 4 bytes
arr+1; //we added 1 to the address, so we moved 1 byte
Basically the sizeof(int) is 4 and the sizeof(char) is 1. So "adding 1 to an array" is not as simple as it looks.
So now, back to the question, why is arr+1 different from &arr+1? The first one is adding 1 * sizeof(char)=1 to the address, the second one is adding 1 * sizeof(arr)=10 to the address.
This is why even though they are both "only adding 1" they give different results.

What do parentheses in a C variable declaration mean?

Can someone explain what this means?
int (*data[2])[2];
What are the parentheses for?
In C brackets [] have a higher precedence than the asterisk *
Good explanation from Wikipedia:
To declare a variable as being a
pointer to an array, we must make use
of parentheses. This is because in C
brackets ([]) have higher precedence
than the asterisk (*). So if we wish to declare a pointer to an array, we need to supply parentheses to override this:
double (*elephant)[20];
This declares that elephant is a
pointer, and the type it points at is
an array of 20 double values.
To declare a pointer to an array of
pointers, simply combine the
notations.
int *(*crocodile)[15];
Source.
And your actual case:
int (*data[2])[5];
data is an array of 2 elements. Each element contains a pointer to an array of 5 ints.
So you you could have in code using your 'data' type:
int (*data[2])[5];
int x1[5];
data[0] = &x1;
data[1] = &x1;
data[2] = &x1;//<--- out of bounds, crash data has no 3rd element
int y1[10];
data[0] = &y1;//<--- compiling error, each element of data must point to an int[5] not an int[10]
There is a very cool program called "cdecl" that you can download for Linux/Unix and probably for Windows as well. You paste in a C (or C++ if you use c++decl) variable declaration and it spells it out in simple words.
If you know how to read expressions in C, then you're one step away from reading complicated declarations.
What does
char *p;
really mean? It means that *p is a char. What does
int (*data[2])[5];
mean? It means that (*data[x])[y] is an int (provided 0 <= x < 2 and 0 <= y < 5). Now, just think about what the implications of that are. data has to be... an array of 2... pointers... to arrays of 5... integers.
Don't you think that's quite elegant? All you're doing is stating the type of an expression. Once you grasp that, declarations will never intimidate you again!
The "quick rule" is to start with the variable name, scan to the right until you hit a ), go back to the variable name and scan to the left until you hit a (. Then "step out" of the pair of parentheses, and repeat the process.
Let's apply it to something ridiculous:
void **(*(*weird)[6])(char, int);
weird is a pointer to an array of 6 pointers to functions each accepting a char and an int as argument, and each returning a pointer to a pointer to void.
Now that you know what it is and how it's done... don't do it. Use typedefs to break your declarations into more manageable chunks. E.g.
typedef void **(*sillyFunction)(char, int);
sillyFunction (*weird)[6];
data[2] - an array of two integers
*data[2] - a pointer to an array of two integers
(*data[2]) - "
(*data[2])[2] - an array of 2 pointers to arrays of two integers.
If you have an array:
int myArray[5];
int * myArrayPtr = myArray;
Would be perfectly reasonable. myArray without the brackets is a pointer to an int. When you add the brackets its like you deference the pointer myArray. You could write...
myArrayPtr[1] = 3;
Which is perfectly reasonable. Using parenthesis just makes things harder to read and understand IMO. And they show that people don't understand pointers, arrays, and pointer arithmetic, which is how the compiler or linker goes from one to the other. It seems with parenthesis you do get bounds checking though.

Resources