首页 > 解决方案 > Question about the equivalence of pointers and arrays in C

问题描述

I am trying to test my understanding of pointers and wrote the following piece of code:

#include <stdio.h>
int main(){
    char array_of_chars[]="array of chars";
    char *pointer_to_a_char="pointer to a char";
    return 0;
}

My justification for why the 2 lines of code are equivalent ways to define a string are that:

The first creates an array of indefinite size (limited by the memory available in the stack?) which stores variables of type char .

The second creates a pointer to a variable of type char, which by the * notation we are then funneling through to where that memory address points to in the RAM and are then writing, from that point, our string.

The above compiles without error.

This new code however, gives a warning.

New code:

#include <stdio.h>
int main(){
    int myint = 5;
    int *pointer_to_an_int = 5;
    return 0;
}
 warning: initialization makes pointer from integer without a cast [-Wint-conversion]
  int *pointer_to_an_int = 5;

I just wanted to know why we get a warning in the second case, but not in the first.

I have a feelings its something to do with the fact that in the first case we are defining an array, which is a memory address but in the second case we are defining a single variable which is different? I don't know the reason for the warning exactly and was hoping someone can explain.

标签: c

解决方案


Oops, you still need to practice C language...

The first creates an array of indefinite size (limited by the memory available in the stack?) which stores variables of type char .

Not exactly: it creates an array, the size of which will be defined by the initializer. So it is seen by the compiler as:

char array_of_chars[15]="array of chars";  // 14 characters + the terminating null

That being said, it is the idiomatic way to initialize a char array...

The second creates a pointer to a variable of type char, which by the * notation we are then funneling through to where that memory address points to in the RAM and are then writing, from that point, our string.

Not exactly. "pointer to a char" is a string literal, which can only be used as if it was a const char array(*). So this is roughly equivalent to:

const char arr[18] = "pointer to a char";      // we have a const char array "somewhere"
char *pointer_to_a_char = arr;                 // (2)

So you now have a non const pointer to a const array... Undefined Behaviour is guaranteed if you later use something like pointer_to_char[2] = 'c';!

BTW: in line (2), arr is an array used as a value, so it decays (it is the C wording) to a pointer to its first element. That is the reason why you initialize you pointer with a pointer value, but with a constness problem.

Now for your question:

int *pointer_to_an_int = 5;

This creates a pointer to int and initializes the pointer with the value 5. So it is almost equivalent to:

int *pointer_to_an_int;
pointer_to_an_int = (int *) 5;

This kind of initialization makes sense in low level code when some hardware registers are mapped at well known addresses, so the compiler accepts it. But here UB is guaranteed if you use something like int j = *i; and in many implementations you will get a segment fault by accessing memory not available to the process.


(*) On a language lawyer point of view a string literal is just a char array (non const), because char *txt = "foo"; was a common idiom in older versions of C language. But changing any element in it is explicitely undefined behaviour to allow compilers to store them in read only memories. Long story made short, we should just remember that is should be used as is is was const.


推荐阅读