This question already has answers here:
What happens if I define a 0-size array in C/C++?
(8 answers)
Closed 8 years ago.
Me and a friend of mine are arguing about that so we thought
here we can get an appropriate answer, with the corresponding explanation.
int a[0];
is a[0] an array and does it have any advantages?
(I didn't only want to know what happened if I defined a and a[0] but also want to know the advantages and how it was more than just the variable.)
As a standalone stack variable, it is not useful. However, as the last member of a struct, it can be used as a variable length array and doing this used to be a common technique. For example:
struct foo {
int a[0];
};
struct foo* bar = malloc( sizeof *bar + 10 * sizeof *bar->a );
/* now you can (possibly) use bar->a as an array of 10 ints */
Note that this is a non-standard, non-portable hack and is certainly not good practice in new code.
YES, they are different according to their functionality.
Lets first get into their memory address.
int a[0];
printf("%p / %p", &a[0], &a);
As you can test a[0] uses the same address as a.
That means they are the same, but that doesn't mean their behaviour is the same.
That because &a aways points to a[0] which is the only one memory area allocated here.
However.. despite the logics, a[0] IS considered array.
Many people say that an array needs to have more then 1 memory block used, but thats wrong.
And that is because of the index operator [] which is what actually makes something an array. (systematic arrangement of objects)
Even if the object is one as it appears in here a[0] it is accepted as an array by the compiller and the debug. And you will have to
initialize the array in case you want to assign value INTO it.
Valid:
int a[] = {1};
Valid:
int a[0] = {1};
Invalid:
int a[0] = 1;
On top of that, converting a pointer to the array is valid as follows:
int a[0];
int* p;
p = a;
However you can't just set p to point into a one block of memory, it is reserved for the datatype. At the end we have an integer that points to itself.
The conclusion is that the compiler/debug and you by yourself can threat it like an array, but you can't use it.
(Or at least to expect propper result)
All that means that the difference between a an a[0] is the ability of a to point to its address.
Related
If I have:
int A[10][20];
printf("%p",A[3]);
it will print the address of A[3][0].
However, I'd like to know if this one dimensional array A[3] containing pointers really exists, or it is calculated in some way.
The way you have defined A means that the compiler will allocate for it a contiguous block of memory large enough to hold 10 x 20 (200) integers; see here (scroll down to "Multidimesional arrays"). As I'm sure you realize, if you were to do printf("%p", A); you would see the address of the beginning of that allocated block.
Now, when the compiler sees the expression A[3], it will add what it calculates as the necessary amount of "integer sizes" to the base address (that of A, or A[0][0]); in this case, it will add "3" (the index specified) multiplied by the combined size of all the other dimensions (in this case, there's only one, which is 20).
So, in your case, there is no actual array of pointers; just a memory block that the compiler can interpret according to how you described any part(s) of it.
However, in a more versatile approach, one can actually define a 2D array in terms of an actual array of pointers, like so:
int **A;
A = malloc(10 * sizeof(int*));
for (int n = 0; n < 10; ++n) A[n] = malloc(20 * sizeof(int));
In this case, using printf("%p",A[3]); would still be valid, but it would give a very different offset value from printf("%p",A); or printf("%p",A[0]);.
It's also, perhaps, worth noting that, even though these two different declarations for A can both resolve an individual element through an expression like A[i][j] (but the compiler would evaluate the addresses differently), there is here scope for major confusion! When, for example, passing such an array to a function: if the function expects data allocated in the second form, and you give it an array defined in the first form (and vice versa), you're gonna get major undefined behaviour .
yes there is a way to calculate the position:
for A[i][j]
the position of the memory block will be
pos = A + i*(number_of_columns_in_each_row) + j
here A is the pointer to the first element of the array
However, I'd like to know if this one dimensional array A containing pointers really exists, or it is calculated in some way.
The way you defined the array A :
int A[10][20];
does not contain any pointers as elements of the array. it contains only integer elements.
if you want to make an array of pointers, which should be assigned to int-variables is defined like that:
int *A[10][20];
You also can set a pointer to the start of the array, which means element [0] [0]
by using:
int *pointer;
int *A[10][20];
pointer = &A;
You also be able to set the pointer slightly forwards according to each element by increase the pointer.
pointer++;
This question already has answers here:
Is an array name a pointer?
(8 answers)
Closed 4 years ago.
So, in C, this perfectly works:
int myArray[] = {1, 2, 3};
why does the following give me a runtime error when accessing an element?
int * myArray2 = {1, 2, 3};
myArray2[0];
when myArray2[0] basically means *myArray2, which does also not work?
I think that the fundamental difference is that declaring an array implicitly allocates memory, while declaring a pointer does not.
int myArray[3]; declares an array and allocates enough memory for 3 int values.
int myArray[] = {1,2,3}; is a little syntactic sugar that lets the size of the array be determined by the initialization values. The end result, in terms of memory allocation, is the same as the previous example.
int *myArray; declares a pointer to an int value. It does not allocate any memory for the storage of the int value.
int *myArray = {1,2,3}; is not supported syntax as far as I know. I would expect you would get a compiler error for this. (But I haven't done actual C coding in years.) Even if the compiler lets it through, the assignment fails because there is no memory allocated to store the values.
While you can deference a pointer variable using array syntax, this will only work if you have allocated memory and assigned its address to the pointer.
Pointer and Array are different. One difference between them is the subject of your question. When you define an array with the specified size, you have enough memory to initialize it.
However, in the pointer, you should allocate the memory to initialize it. Hence, you should first allocate the memory using a function like malloc and point the pointer to the allocated memory. Therefore, the problem with the second code is you want to access the part of the memory which is not allocated.
You can correct it likes the following:
int *myarray2 = malloc(3*sizeof(int));
myarray2[0] = 1;
myarray2[1] = 2;
myarray2[2] = 3;
While doing some research on multi-dimensional arrays in C and how they're stored in memory I came across this: "Does C99 guarantee that arrays are contiguous?". The top-voted answer states that "It must also be possible to iterate over the whole array with a (char *)," then provides the following "valid" code:
int a[5][5], i, *pi;
char *pc;
pc = (char *)(&a[0][0]);
for (i = 0; i < 25; i++)
{
pi = (int *)pc;
DoSomething(pi);
pc += sizeof(int);
}
The poster then goes on to say that "Doing the same with an (int *) would be undefined behavior, because, as said, there is no array[25] of int involved."
That line confuses me.
Why does using a char pointer constitute as valid / defined behavior while substituting it with an integer pointer doesn't?
Sorry if the answer to my question should be obvious. :(
The difference between using a char* and an int* is strict aliasing rules: If you access (&a[0][0])[6] (i. e. via an int*), the compiler is free to assumes that the access [6] does not leave the array at a[0]. As such, it is free to assumes that (&a[0][0]) + 6 and a[1] + 1 point to different memory locations, even though they don't, and reorder their accesses accordingly.
The char* is a difference because it is explicitly exempted from strict aliasing rules: You can cast anything to a char* and manipulate its bits through this pointer without invoking undefined behavior.
The standard is very clear that if you have:
int a[5];
int* p = &a[0];
Then
p += 6;
is cause for undefined behavior.
We also know that memory allocated for a 2D array such as
int a[5][5];
must be contiguous. Given that, if we use:
int* p1 = &a[0][0];
int* p2 = &a[1][0];
p1+5 is a legal expression and given the layout of a, it is equal to p2. Hence, if we use:
int* p3 = p1 + 6;
why should that not be equivalent to
int* p3 = p2 + 1;
If p2 + 1 is legal expression, why should p1 + 6 not be a legal expression?
From a purely pedantic interpretation of the standard, using p1 + 6 is cause for undefined behavior. However, it is possible that the standard does not adequately address the issue when it comes to 2D arrays.
In conclusion
From all practical points of view, there is no problem in using p1 + 6.
From a purely pedantic point of view, using p1 + 6 is undefined behavior.
Either an int pointer or a char pointer should work, but the operation should differ slightly in these two cases. Assuming sizeof(int) is 4. pc += sizeof(int) moves the pointer 4 bytes forward, but pi += sizeof(int) would move 4 times 4 bytes forward. If you want to use an int pointer, you should use pi ++.
EDIT: sorry about the answer above, using an int pointer does not comply with C99 (although it usually practically works). The reason is explained well in the original question: pointer goes across an array is not well defined in the standard. If you use an int pointer, you would start from a[0], which is a different array from a[1]. In this case, an a[0] int pointer cannot legally (well-defined) point to a[1] element.
SECOND EDIT: Using a char pointer is valid, because the following reason given by the original answer:
the array as a whole must be working when given to memset, memmove or memcpy with the sizeof. It must also be possible to iterate over the whole array with a (char *).
From section 6.5.6 "Additive Operators"
For the purposes of these operators, a pointer to an object that is not an element of an
array behaves the same as a pointer to the first element of an array of length one with the
type of the object as its element type.
So it is reasonable.
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:
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.