2

I am currently learning C with http://c.learncodethehardway.org/book/ and we are supposed to figure out some weird things on our own.

First of all I found this webpage that has already helped me understand some things about functions and function definitions and pointers and their use. Now the problem comes to when I see some "string" definitions.

Please correct me if these assumptions I am going to make are wrong:

char name[] = "John"; // creates an array of characters with these four letters + '\0'

A "string" is just an array of characters ending with '\0'.

I also read that a * before an identifier usually means that it is a pointer. For example:

int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?

If those assumptions are right, I don't understand what is going on here:

char *name = "John";

Is that a pointer to a string? Or is it another way of defining a string?? If so, is

char *name[] = "John";

the actual pointer to the "string"? (which is just an array of characters?).

EDIT Reading all your answers and comments I must ask another thing. "type char *" is a pointer to a char, right?

RGS
  • 964
  • 2
  • 10
  • 27
  • `char *name = "John";` : `const char name_tmp[]="John"; char *name = name_tmp;` – BLUEPIXY Jul 17 '14 at 10:56
  • `char *name[]` : array of `char*`. e.g `char *name[] = {"John"};` – BLUEPIXY Jul 17 '14 at 10:58
  • It is important to know that char arr[] and char *arr are two different things. A pointer points to the starting memory location of the continuous characters of the string while an array is a set of memory blocks assigned for the characters. – Shashish Chandra Jul 17 '14 at 11:00
  • @BLUEPIXY sorry, but I didn't understand anything you said. is "array of `char*`" an array of pointers to characters? – RGS Jul 17 '14 at 11:04
  • @RSerrao yes, but that's array of `char*`. What you have is array of `char`. – Fred Foo Jul 17 '14 at 11:04
  • "array of char*" an array of pointers to `char`. – BLUEPIXY Jul 17 '14 at 11:05

6 Answers6

4

This statement

char name[] = "John"; 

means that name is an array of characters that will contain the following sequence

{ 'J', 'o', 'h', 'n', '\0' }

In fact you could write

char name[] = { 'J', 'o', 'h', 'n', '\0' };

These records are equivalent.

As for this statement

char *name = "John";

then there are the following actions made by the compiler. It creates an array of type char[5] to store the string literal and then assigns the address of the first character of this array to pointer name. So name will contain the address of the first character of the string literal. Though string literals in C has types of non-const arrays you may not change them. So it would be better to write

const char *name = "John";

For this statement

char *name[] = "John";

the compiler shall issue an error becuase to initialize an array (except character arrays) there must be used a brace-init list. The valid record will look as

char *name[] = { "John" };

In this case the array would have only one element of type char * that would point to the first character of the string literal. The string literal itself would be placed in memory as an array of type char[5] by the compiler.

As for the difference between records

int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?

and

char *name = "John";

then in the first record there is a scalar object myNum, You have to apply operator & that to get its address. While in the second record the string literal is an array. In expressions such this it is adjasted by the compiler to a pointer to the first element of the array. So you have no apply operator & for the string literal. The expression in the right side has already type char *.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?

The type of myNum is int, which contains integer.

The type of myNum_pointer is int *, which contains address of integer variables.

-----------------------------------------------------
variables: | myNum         | myNum_pointer          |
-----------------------------------------------------
address  : | 0x12341234    | 0x12341238             |
-----------------------------------------------------

the & operator gets the address of operand. So, &myNum is equal to 0x12341234

So the variables are initialized like this:


variables: | myNum          | myNum_pointer  |
---------------------------------------------
address  : | 0x12341234     | 0x12341238     |
---------------------------------------------
value    : | 18              | 0x12341234    |
---------------------------------------------

Now

  char *name = "John";

defines name as a pointer to the first character in the string. The assignment means that as soon as the program loads, the pointer is set to hold the address of where the string is stored. It put string literal in read only part. pointers only hold an address, they cannot hold all the characters in a character array. This means that when we use a char * to keep track of a string, the character array containing the string must already exist.

EX>

char name[] = "John";
char *name2;
name2=name;

name @2000
----------------------
| j | o | h | n | \0 |
----------------------

name2 @3000
--------
| 2000 |
--------

Also

For pointer to string array you can define it like

char * mystr[10];

After that you can initilize it by like

mystr[i]="john";

OR at define time also you can initialize like

const char *digitnames[] = {"zero", "one", "two", "three",
        "four", "five", "six", "seven", "eight", "nine"};
Jayesh Bhoi
  • 24,694
  • 15
  • 58
  • 73
1
char *name = "John";

defines an anonymous, statically allocated array of five bytes holding {'J', 'o', 'h', 'n', 0}, and declares a pointer name which initially points to the first element of the aforementioned array. That's the rule in C: an array "decays" into a pointer to its first element.

char *name[] = "John";

is invalid. It defines an array of char as before, but then tries to assign it to an array of char pointers, which makes no sense. The use case for char *[] is to store (pointers to the first char of) multiple strings:

char *names[] = {"John", "Mary"};

Read as: names is an array ([]), each element of which is a char*; this array we initialize with the elements "John" and "Mary", and since we're initializing pointers, these char arrays decay into pointers to their first elements.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • so in the last example, the array `names` holds 2 pointers?? each one pointing at the first letter of either John or Mary? – RGS Jul 17 '14 at 11:06
  • It's better to define a string as `char name[] = "John"`, because arrays and pointers are not the same thing(http://stackoverflow.com/questions/1641957/is-array-name-a-pointer-in-c), so in `char *name = "John";` name is not an array. – Nasser Al-Shawwa Jul 17 '14 at 11:12
  • @Nasser: that depends, really. Sometimes you actually want to reassign the pointer. Also in the "array of strings" case pointers are much more convenient when the strings are not of equal length. – Fred Foo Jul 17 '14 at 11:27
  • @larsmans sure, but regardless of convenience, this is about correctness. Some compilers will warn you that `char *name = "John"` is deprecated notation. And besides, there are differences in behaviour, `*name` and `name[]` are not interchangeable. Try calling `sizeof name` and see what comes out after each representation. – Nasser Al-Shawwa Jul 17 '14 at 11:39
  • @Nasser I don't disagree with you, but I would point out sometimes you need a pointer anyway :) – Fred Foo Jul 17 '14 at 11:43
1

Let's look at the line:

int myNum = 18;

In that line, you define a variable which has several properties:

  1. Identifier : the variable name myNum
  2. Type : int
  3. Address : this is it's location in memory. For the purpose of this explanation, I'm giving it a value of 0xa1, but it could be any value of the sort.
  4. Value: 18

In order to get a variable's address, you use the & operator. In this case, the line:

int *myNum_pointer = &myNum;

On the right hand side, &myNum returns the address of myNum, which in our case evaluates to 0xa1. And we are storing that in a variable called myNum_pointer, which has the type pointer-to-int, which means that it stores the address of an int variable. Because myNum_pointer is a variable in it's own right, it also has it's own properties:

  1. Identifier : the variable name myNum_pointer
  2. Type : int* (pointer-to-int)
  3. Address : it's own location in memory. let's say it's 0xa2.
  4. Value: 0xa1 (the address of myNum).

So, yes, you do need the & operator.

As for the part about the string: Don't define a string in C in this way.

char name[] = "John"; // Good
char *name  = "John"; // Bad

This is because although arrays and pointers are related, they are not the same thing. Some compilers will warn you that the second statement is deprecated in C.

And finally,

char *name[] = "John";

Is incorrect. Because here you are saying the name is an array of pointers to characters, when it's just an array of characters.

"John" is actually a string literal, which is an array of {'J', 'o', 'h', 'n', 0}, where 0 is the null-termination character which signifies the end of a string in C. In fact, without the last 0, {'J', 'o', 'h', 'n'} would simply be an array of characters, and not a proper string, which is another important distinction.

Community
  • 1
  • 1
Nasser Al-Shawwa
  • 3,573
  • 17
  • 27
0

I guess that this is a duplicate of hundreds of other qustions, but I'hm going to answer it anyway.

First, the '&' is a unary operator for the adress of a variable. So, for example, &foo could be an adress like 0xffff. So you definitely need the '&', because otherwise, if foo==1, your pointer would be on the adress 0x0001, and if you wanted to change the value, you would get a segfault (I guess it wouldn't even compile).

Second:

char* name="John";

does two things. It allocates an unchangable part in the memory and writes "John\0" into it. You have a pointer to that memory, but you can't change it, e.g write "john\0".

Third:

char* name[]

is a pointer to an array of chars. it can also be written like this:

char** name

or this:

char name[][]

It is actually an array of strings.

Fun fact: a '*' in front of a pointer gives back the value of the object the poiner points to. E.g:

int i=0;
int* pi;
pi=&i;
i==*pi  //this is true
0

To answer your question of:

int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?

Yes, you need the & (which is the Address-of operator). This assigns the pointer myNum_pointer the address of myNum. If you take out the &, you are assigning the number in myNum directly to the pointer, which is a bad thing, and not what is intended. The problem would occur when you later use myNum_pointer, and it points to memory address 18 instead of the memory address of the myNum variable (if the compiler even accepts it). This would likely cause a segmentation fault at run time, which can be tricky to debug.

Jonathan
  • 1,050
  • 1
  • 12
  • 36