A
A
Ali Aliyev2013-11-05 00:56:22
C++ / C#
Ali Aliyev, 2013-11-05 00:56:22

Strange behavior of arrays in C

Slowly I'm starting to get into C. Unfortunately, I am far from low-level programming, so I will go straight to a stupid question.

We have an array:

#include <stdio.h>

int main(int argc, char *argv[]) {
    char *name = "Hello World";
    printf("%p", &name);
    printf("%p", name);
    printf("%s", name);
}


Why does the first and second print give the address of the first element in the array, and at the same time, when calling name, the entire string is returned, and also sizeof (name) returns the size of the entire string in the array? There is one more question about arrays: you can get an array element like this (that is, work with them as with pointers) *(name + 1), it turns out that arrays themselves are pointers? Where can you read more about this?

PS Why do we need pointers to pointers?

Thank you in advance.

Answer the question

In order to leave comments, you need to log in

7 answer(s)
@
@ntkt, 2013-11-05
@ali_aliev

An array as a variable in C is an alias for the address in memory where its first element lies.
An array, neither in machine code nor in memory, strictly speaking, does not exist . There is only its "content" - its elements.
When accessing an array element, actions are performed by the machine directly on its contents at the calculated address.
The array itself does not exist.
Whenever you work with an array in C, the compiler uses either a pointer to the first element of the array (for example, when you pass an array to a function), or the address of the first element of the array, and the machine then works with it.
A pointer in C is a variable that holds an address in memory.
Pointer in machine code and memory - exists. It has a value - a number the size of a machine bit, and the value of the number is an address in memory.
Pointer as a number - can be passed in registers, lie on the stack, etc.
When accessing a byte/word/dword/… by offset through a pointer, the pointer is dereferenced in machine code (its value=address is taken explicitly), i.e. in native code, slightly different actions occur than in the case of an array.
If you want to understand completely, open an assembler book next to it, compile your examples with the output of intermediate assembler code (or look in a disassembler), and carefully compare step by step.
By the way, here is a decent description of the differences in English:
eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c/

M
Mikhail Vasilyev, 2013-11-05
@mickvav

Kernigan, Ritchie - language C.http://lib.ru/CTOTOR/kernigan.txt
Yes, arrays are pointers. A pointer to a pointer is needed, for example, when you want to tell the function "do something and put the result of a length unknown to me here." You simply pass a pointer to a pointer to the function, it allocates / reallocates what it needs, and you are already working with the result.

M
Mikhail Vasilyev, 2013-11-05
@mickvav

Here, apparently, the trick is that you created a constant array during initialization. Something tells me that this behavior (the address of the pointer is equal to the address of the array itself) is typical for such a situation - the compiler decides that since the array is a constant on the stack, why allocate separate memory for its address? In the same place, everything is known at the compilation stage ... But most likely this behavior is a compiler-specific example of bad code ;)

M
Mikhail Vasilyev, 2013-11-05
@mickvav

On the question - I checked it, it gives me different addresses. What compiler did you see this on?

M
Maxim Moseychuk, 2013-11-05
@fshp

The first and second print will give different results.
The array is placed on the stack, the name variable is also placed there, where the address to the first element of the array is stored. At the end of the char array, the compiler adds a character with code 0x00 - a sign of the end of the string. This is why printf outputs the correct number of characters.
The first print will give the address of the name variable, and the second will print the content (the address of the 'H' character).
The third one will output all characters starting from the address stored in the name variable until 0x00 is encountered.
sizeof is done at compile time, native code will have constants instead.
sizeof(name) will return the size of the pointer, not the size of the array, because you've defined a pointer, not an array, and assigned it the address of an array.

char name_array[] = "Hello World!"

This is already an array, and sizeoff will return its size, because it is known at compile time.
Arithmetic operations can be performed on pointers. For example *(name+i) is equivalent to name[i].
Not i will be added to the address, but i*sizeof(*name), i.e. the size of the pointer type multiplied by the number. We get the i-th element. The compiler will take care of this. To get an arbitrary address, you must cast the pointer to the void type.
Arrays are not pointers. There are arrays, there are pointers. There are addresses. We take the address of the array and store it in a pointer. In turn, a pointer is a variable, and it is also located at some address. Pointers to pointers appear here (the hierarchy is not limited). For example multidimensional arrays.

V
Vladimir Dubrovin, 2013-11-05
@z3apa3a

sizeof(name) returns the size of the entire string in the array

here you are confusing something, should return the size of the pointer, i.e. 4 or 8 depending on the bit depth of the platform.
You don't have arrays at all in your example, except in the initializer. An array is
char name[]={...}
in this case, name is a constant pointing to an array, sizeof for it is the size of the array, the constant does not have its own address, so &name in this case returns the address of the array, i.e. name itself. In all other respects, it is completely equivalent to const char *, for which reason *(name +i) can be used.
The fact that you can not specify the size in parentheses during initialization is a feature of initialization in C; if there is an initializer, the size is calculated during compilation.
char* name={...} differs from the previous example in that name is not a constant, but a variable for which additional memory is allocated (4/8 bytes on 32/64-bit systems, respectively). Accordingly, sizeof(name) returns the size of a variable, and &name returns the address of that variable.

M
Mikhail Vasilyev, 2013-11-05
@mickvav

If you write
char a[]="hello";
Then sizeof(a) will be 6. In the gcc that I have on hand. Eg how much stack was given for this array.
And if
char *a="hello";
Then sizeof(a) will be 8 Eg the size of the pointer. And &a will (expectedly) be different from a.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question