1

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.

Vishal Jain
  • 443
  • 4
  • 17
  • `int myint[] = 5;` wouldn't work either... – ikegami Mar 11 '20 at 16:16
  • They are different. `array_of_chars` is an array. `pointer_to_char` points to a memory location initialized to hold the string constant (which may or may not be writable). – William Pursell Mar 11 '20 at 16:17
  • 1
    Does this answer your question? [What is the difference between char s\[\] and char \*s?](https://stackoverflow.com/questions/1704407/what-is-the-difference-between-char-s-and-char-s) – dandan78 Mar 11 '20 at 16:43
  • The equivalent is, for example, `int array_of_ints[] = { 102, 111, 111, 98, 97, 114 };` – pmg Mar 11 '20 at 16:48
  • `pointer_to_a_char` is a pointer that points to a _string_. `array_of_chars` is an array that contains a _strng_. – chux - Reinstate Monica Mar 11 '20 at 18:05

2 Answers2

6

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.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • "is a string literal, which is a const char array" --> Not quite. A _string literal_ is a non-`const` `char` array of some size. Useful to treat it as a `const` array though. Rest is good. – chux - Reinstate Monica Mar 11 '20 at 17:59
  • @chux-ReinstateMonica: I know, a string literal is declared as is it was a non const char array, but it is UB to try to modify it... And I even know the rationale behind with all the involved compatibility reasons. I wanted to avoid that precision by lazyness but you are right, it makes the post incorrect. I have tried to introduce it. Feel free to edit, if my wording is not good enough - English is not my first language... – Serge Ballesta Mar 11 '20 at 18:22
2

These two lines are very different:

char array_of_chars[]="array of chars";
char *pointer_to_a_char="pointer to a char";

The first is shorthand for:

char array_of_chars[]= {'a', 'r', ... , '\0' };

which creates and initializes a local array variable. The second creates a pointer and initializes it with the address of a string constant. The most significant functional differences are that the string constant may or may not be writable, and the pointer can be modified to point to something different.

Pointers are not arrays. Arrays are not pointers.

William Pursell
  • 204,365
  • 48
  • 270
  • 300