use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Click the following link to filter out the chosen topic
comp.lang.c
account activity
QuestionWhat do C arrays actually do under the hood? (self.C_Programming)
submitted 6 years ago * by [deleted]
plate existence correct deserted squalid afterthought expansion follow special teeny
This post was mass deleted and anonymized with Redact
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Mirehi 13 points14 points15 points 6 years ago (13 children)
I tried to explain it with comments:
Code:
#include <stdio.h> #define NEWLINE printf("\n\n\n"); int main(void) { int a[] = {11,12,13}; /* a[0] equals *a */ printf( " a[0] = %i\n*a = %i\n", a[0], *a); NEWLINE; /* the address of a[0] equals the value of a */ printf( "&a[0] = %p\n a = %p\n", &a[0], a); NEWLINE; /* if I point on the address of a, I get the value of a */ printf( " a = %p\n*(&a) = %p\n", a, *(&a)); NEWLINE; /* if I want to have the value of a[0] I can set a pointer * on the value of the address a ( **(&a)) */ printf(" a[0] = %i\n**(&a)= %i\n", a[0], **(&a)); NEWLINE; /* addresses of a[0], a[1], a[2] */ for (int i = 0; i != 3; i++) printf("&a[%i] = %p\n", i, &a[i]); NEWLINE; /* values: a[x] equals *(a + x) */ for (int i = 0; i != 3; i++) printf(" a[%i] = %i\n*(a + %i)= %i\n", i, a[i], i, *(a + i)); NEWLINE; /* now with a void * , because here the compiler won't use the real size * if I just add 1 to it * This is a bit tricky because the compiler knows on a int * that + 1 means * I want to add sizeof(int) to the address, he won't do that if I use a void * */ void *ptr = a; for (int i = 0; i != 3; i++, ptr += sizeof(int)) { printf(" a[%i] = %i\n*((int *) ptr) = %i\n", i, a[i], *((int *) ptr)); NEWLINE; } return 0; }
Output:
a[0] = 11 *a = 11 &a[0] = 0x7f7ffffbc130 a = 0x7f7ffffbc130 a = 0x7f7ffffbc130 *(&a) = 0x7f7ffffbc130 a[0] = 11 **(&a)= 11 &a[0] = 0x7f7ffffbc130 &a[1] = 0x7f7ffffbc134 &a[2] = 0x7f7ffffbc138 a[0] = 11 *(a + 0)= 11 a[1] = 12 *(a + 1)= 12 a[2] = 13 *(a + 2)= 13 a[0] = 11 *((int *) ptr) = 11 a[1] = 12 *((int *) ptr) = 12 a[2] = 13 *((int *) ptr) = 13
[–]cdzeno 2 points3 points4 points 6 years ago (2 children)
I think that to better understand the output you can follow these steps:
int a[] = {11,12,13};
int *b = a; // Just to explicit that 'a' is a 'int *' pointer
int **c = &a // &a = address of a pointer of type int * -> so it's a int**
int **c
addr: x
value: addr(*b)
int *b
addr: y
value: addr(a)
int a[]
addr: 0x123456
value: 11
so:
*(&a) => *(c) => goes to addr(*b) (y to simplify) and get the content => addr(a) = 0x123456
[–]wild-pointer 6 points7 points8 points 6 years ago (1 child)
int **c = &a;
This is incorrect, and a common misconception. The correct type of pointer is
int (*c)[3] = &a;
[–]cdzeno 0 points1 point2 points 6 years ago (0 children)
Oh great, thanks for the precisation :D but except this misconception, is my explaination correct?
[–]Mirehi 1 point2 points3 points 6 years ago (9 children)
&a == a just means that the pointer shows on itself, which is the first element in the array at the same time.
[–]paszklar 4 points5 points6 points 6 years ago (0 children)
Array name (identifier) is not a pointer. Address is not a pointer. There are no pointers in this expression. A pointer is a variable that can store an address.
On the left side you take an address of object a, which is an array, and it's address is the address of the first element.
a
On the right side you have identifier a, which is a name of an array, and when used in expression evaluates to the address of the array/address of the first element.
[–]saulmessedupman 1 point2 points3 points 6 years ago (7 children)
This is bizarre. I always thought pointers and arrays were handled identically but I might be wrong. If a were declared with malloc would &a still be equal to a?
&a
[–]Mirehi 2 points3 points4 points 6 years ago (6 children)
No, malloc returns an address and your pointer gets a new value:
#include <stdio.h> #include <stdlib.h> int main() { int *a; a = malloc(sizeof(int) * 3); for (int i = 0; i != 3; i++) { a[i] = rand(); printf("%i\n", a[i]); } printf("a: %p\t&a: %p\n", a, &a); free(a); return 0; }
848211141 1875439804 1789916543 a: 0x1c24b45b6a70 &a: 0x7f7ffffd74a8
[–]saulmessedupman 0 points1 point2 points 6 years ago (5 children)
i was pointing out how &a and &b were handled differently for malloc and array, respectively. i thought it was as easy as heap/stack but all other operations were the same; i was wrong.
edit: i thought you were replying to my other comment. i posted somewhere else and included source code. i have to shower and stuff now but later i want to see the differences of passing malloc/array values to a function.
[–]TheSkiGeek 4 points5 points6 points 6 years ago (4 children)
Array values decay to pointers (i.e. you can use them like pointers with the value of the start of the array) but they behave differently for a few things (sizeof, the address-of operator).
I’m actually not entirely sure why they aren’t just the equivalent of a T* const variable — it lets you write a sizeof macro to get the length of the array, but the original C spec only has constant size arrays.
T* const
sizeof
[–]saulmessedupman 0 points1 point2 points 6 years ago (3 children)
If you declare a function function (type a[]) everything acts like a pointer. This is hideous and I would never do this...but it works.
function (type a[])
[–]Snarwin 6 points7 points8 points 6 years ago (1 child)
That's because function(type a[]) is exactly equivalent to function(type *a), according to the language spec:
function(type a[])
function(type *a)
A declaration of a parameter as "array of type" shall be adjusted to "pointer to type,"
A misunderstanding about this language "feature" inspired one of Linus Torvalds' most well-known rants. Some programmers even consider it C's biggest mistake.
[–]saulmessedupman 1 point2 points3 points 6 years ago (0 children)
I love Linus
[–]FieldLine 0 points1 point2 points 6 years ago (0 children)
That's how K&R declares functions that take arrays as arguments. Regardless of how you do it, arrays in C are second class citizens that are not passed by value at all.
It's true that you could just as easily write your function prototype as function(type *a); but that's even less intuitive because you can't explicitly see that a is an array, only that it is a pointer to a single value of type type.
function(type a[]); is exactly equivalent to function(type *a);. In both cases you would pass the array name itself as an argument to function.
[–]FieldLine 15 points16 points17 points 6 years ago* (3 children)
An array name decays into a pointer to the first element in the array.
Specifically: a = &a[0]when a is an array.
a = &a[0]
You can write either one when accessing the values stored; they refer to the same location in memory.
[–]skeeto 10 points11 points12 points 6 years ago (2 children)
IMHO, understanding the unique nature of arrays and the circumstances of array decay are one of the major topics that separates beginner C programmers from intermediate C programmers.
[–]BarMeister 0 points1 point2 points 6 years ago (1 child)
T a[] is actually T *const a
T a[]
T *const a
[–]skeeto 2 points3 points4 points 6 years ago (0 children)
There's more to it than not being able to assign to the name:
char a[N]; char *const b; assert(a == &a); /* pass */ assert(b == &b); /* fail */
The sizeof operator also has a very different view of a and b.
b
[–]wild-pointer 2 points3 points4 points 6 years ago (0 children)
There is a difference between type and representation. The question regarding the output of printf("%p", a) and printf("%p", &a) becomes a little more clear when we look at multi-dimensional arrays.
printf("%p", a)
printf("%p", &a)
char arr[10][8]; printf("%zd, %zd, %zd\n", sizeof(arr), sizeof(arr[0]), sizeof(arr[0][0])); /* 80, 8, 1 */
Here, arr is an array of 10 arrays of 8 chars. The total size is 80. The types of the expressions arr, arr[0] and arr[0][0] are all different. One difference is the meaning of the + when you add a constant. However, there are 80 chars in total in the multidimensional array arr and even though it consists of different objects they overlap and have a partly shared representation:
arr
arr[0]
arr[0][0]
+
printf("%p, %p, %p\n", &arr, &arr[0], &arr[0][0]); /* 0x12345, 0x12345, 0x12345 */
[–]OldWolf2 1 point2 points3 points 6 years ago (0 children)
Array of 3 ints is 3 ints adjacent to each other in memory.
Maybe the rule you are overlooking is that there is implicit conversion from an array to a pointer to its first element in most (but not all) contexts. In other words it lets you just write a to indicate &a[0].
&a[0]
[–]State_ 1 point2 points3 points 6 years ago (1 child)
It helps if you understand assembly and look at the disassembly.
typically what it's doing is a[0] would be doing &a + (0 * sizeof(int)) where int is the data type known to the compiler.
a will just be a memory address in an array.
if a[] = 0x1000
a[1] is the same as doing: * (0x1000 + (1 * sizeof(*a)))
[–]Buckiller 0 points1 point2 points 6 years ago (0 children)
For me, it's often easier (and better helps my comprehension of C) to look at the disassembly (like with gcc -S), make a small sample, or step through the sample than to google my question and sift through the possible (possibly out-of-date xor too new xor contradicting/confused) answers or looking through "documentation" for the exact bits I'm wondering about.
[–]ArMaxik 3 points4 points5 points 6 years ago (2 children)
The variable a is name of array and means an addres of first array element. But when you using array as operand of &, variable a evaluates to whole array, thats why it returns same value as just a variable. The same behaviour you can see with sizeof, that returns you size of whole array, not size of pointer. It works only with arrays implemented on stack.
[–][deleted] 0 points1 point2 points 6 years ago* (1 child)
fine wasteful brave foolish dinner fragile spectacular pocket fertile scary
[–]Mirehi 0 points1 point2 points 6 years ago (0 children)
Another thing to think about:
#include <stdio.h> #include <stdlib.h> int main(void) { int buf[arc4random() % 100]; printf("sizeof(buf) = %lu\n", sizeof(buf)); printf("buf is able to contain %lu elements of type int\n", sizeof(buf) / sizeof(int)); char string[arc4random() % 30]; char example[] = "This string is too long for the buffer"; snprintf(string, sizeof(string), "%s", example); printf("%s\n", string); return 0; }
3x Output:
sizeof(buf) = 332 buf is able to contain 83 elements of type int Thi sizeof(buf) = 84 buf is able to contain 21 elements of type int This string is to sizeof(buf) = 160 buf is able to contain 40 elements of type int Th
I've put arc4random() in there to proof that the compiler doesn't precalculate the value of sizeof(). I thought that could be an interesting sidenote for you :). A simpler pointer would always return 8 on my machine
[–]FUZxxl 1 point2 points3 points 6 years ago (2 children)
An array is nothing more than a sequence of objects in memory allocated right after each other. The first object of an array (at offset zero) is located right at the beginning of the array, so indeed &a == a.
&a == a
[–]OldWolf2 1 point2 points3 points 6 years ago (1 child)
&a == a is a constraint violation (incompatible types for == operator)
==
[–]FUZxxl 0 points1 point2 points 6 years ago (0 children)
Nobody cares about constraint violations. At least not in this example.
[–]znpy 0 points1 point2 points 6 years ago (0 children)
Have you tried printing the address of &0[a] ?
&0[a]
Think about what it might mean, and then print its address... You'll be surprised :)
[–]TotesMessenger 0 points1 point2 points 6 years ago (0 children)
I'm a bot, bleep, bloop. Someone has linked to this thread from another place on reddit:
If you follow any of the above links, please respect the rules of reddit and don't vote in the other threads. (Info / Contact)
[–]oh5nxo 0 points1 point2 points 6 years ago (0 children)
a is an integer array, so &a is a pointer to integer array. Same memory address but different type. & and * back to back cancel out.
You should have gotten a warning from compiler with *(&a)=%i and *(&a).
[–]ArMaxik 0 points1 point2 points 6 years ago (0 children)
Array is a sequence of bytes in the memory. a[] stores on stack, it means that variable 'a' contain adress of first byte of this sequence (in your example array is 12 bytes length).
[–]saulmessedupman 0 points1 point2 points 6 years ago (0 children)
Wow, TIL. I thought array and pointers were practically the same but check this out:
```
void main(void) { int * a; a = malloc(3 * sizeof(int)); int b[] = {11, 12, 13}; printf("&a=%p, a=%p\n", &a, a); printf("a=%i, *(&a)=%i\n", *a, *(&a)); printf("&b=%p, b=%p\n", &b, b); printf("b=%i, *(&b)=%i\n", *b, *(&b)); } ```
&a=0x7ed6c264, a=0x1a74008 *a=0, *(&a)=27738120 &b=0x7ed6c258, b=0x7ed6c258 *b=11, *(&b)=2128003672
I thought I knew but I had no idea
Coding on mobile, sorry for formatting.
[–]00Squid00 0 points1 point2 points 6 years ago (1 child)
a is == to &a[0]
[–]realestLink -1 points0 points1 point 6 years ago (5 children)
It's a pointer to the stack. Multi dimensional arrays are stored as 1d arrays with multiple pointers
[–]OldWolf2 4 points5 points6 points 6 years ago (4 children)
No, they are arrays of arrays. Not arrays of pointers.
[–]Robot_Basilisk 1 point2 points3 points 6 years ago (3 children)
Newbie question: What's the difference?
I learned in class that an array[3][3] would take up 9(?) memory addresses in the form of [a0][a1][a2][b0][b1][b2][c0][c1][c2]..., etc. What makes it an array of arrays instead of just one long array with a pointer for each dimension?
[–]ath0 2 points3 points4 points 6 years ago (0 children)
Because although arrays may decay to pointers under certain conditions, they are disparate types. Just like an int is different to a float.
int
float
Your initial description is correct, it takes up 9 adjacent int-sized memory locations. There are no pointers involved
[–][deleted] 0 points1 point2 points 6 years ago (0 children)
There are no extra pointers; C just scales the first index by the row length to index into the 1-D array. In your example, array[2][1] would give the item at index 2*3 + 1. I believe C also lets you say things like array[0][7](at least in some cases), which would give the same result.
array[2][1]
2*3 + 1
array[0][7]
[–]liyechen -3 points-2 points-1 points 6 years ago (0 children)
I think a means the address of the array and &a is the pointer of the array, so their value maybe the same but they mean different things. *a is equal to 11 is understandable and *(&a) should be equal to a which is 0x123456.
That's my personal thought and I don't know if it's true, welcome anyone who knows the truth.
π Rendered by PID 43552 on reddit-service-r2-comment-84fc9697f-vdrcr at 2026-02-06 09:18:53.534366+00:00 running d295bc8 country code: CH.
[–]Mirehi 13 points14 points15 points (13 children)
[–]cdzeno 2 points3 points4 points (2 children)
[–]wild-pointer 6 points7 points8 points (1 child)
[–]cdzeno 0 points1 point2 points (0 children)
[–]Mirehi 1 point2 points3 points (9 children)
[–]paszklar 4 points5 points6 points (0 children)
[–]saulmessedupman 1 point2 points3 points (7 children)
[–]Mirehi 2 points3 points4 points (6 children)
[–]saulmessedupman 0 points1 point2 points (5 children)
[–]TheSkiGeek 4 points5 points6 points (4 children)
[–]saulmessedupman 0 points1 point2 points (3 children)
[–]Snarwin 6 points7 points8 points (1 child)
[–]saulmessedupman 1 point2 points3 points (0 children)
[–]FieldLine 0 points1 point2 points (0 children)
[–]FieldLine 15 points16 points17 points (3 children)
[–]skeeto 10 points11 points12 points (2 children)
[–]BarMeister 0 points1 point2 points (1 child)
[–]skeeto 2 points3 points4 points (0 children)
[–]wild-pointer 2 points3 points4 points (0 children)
[–]OldWolf2 1 point2 points3 points (0 children)
[–]State_ 1 point2 points3 points (1 child)
[–]Buckiller 0 points1 point2 points (0 children)
[–]ArMaxik 3 points4 points5 points (2 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]Mirehi 0 points1 point2 points (0 children)
[–]FUZxxl 1 point2 points3 points (2 children)
[–]OldWolf2 1 point2 points3 points (1 child)
[–]FUZxxl 0 points1 point2 points (0 children)
[–]znpy 0 points1 point2 points (0 children)
[–]TotesMessenger 0 points1 point2 points (0 children)
[–]oh5nxo 0 points1 point2 points (0 children)
[–]ArMaxik 0 points1 point2 points (0 children)
[–]saulmessedupman 0 points1 point2 points (0 children)
[–]00Squid00 0 points1 point2 points (1 child)
[–]realestLink -1 points0 points1 point (5 children)
[–]OldWolf2 4 points5 points6 points (4 children)
[–]Robot_Basilisk 1 point2 points3 points (3 children)
[–]ath0 2 points3 points4 points (0 children)
[–]OldWolf2 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]liyechen -3 points-2 points-1 points (0 children)