13

I am reading the chapter on arrays and pointers in Kernighan and Richie's The C Programming Language.

They give the example:

/* strlen:  return length of string s */
int strlen(char *s)
{
    int n;

    for (n = 0; *s != '\0'; s++)
        n++;
    return n;
}

And then say:

“Since s is a pointer, incrementing it is perfectly legal; s++ has no effect on the character string in the function that called strlen, but merely increments strlen’s private copy of the pointer. That means that calls like

strlen("hello, world");  /* string constant */
strlen(array);           /* char array[100]; */
strlen(ptr);             /* char *ptr; */

all work.”

I feel like I understand all of this except the first call example: Why, or how, is the string literal "hello, world" treated as a char *s? How is this a pointer? Does the function assign this string literal as the value of its local variable *s and then use s as the array name/pointer?

Dmitry Minkovsky
  • 36,185
  • 26
  • 116
  • 160
  • Some very good questions/answers on SO about strings, arrays, pointers, and their relationships. [Just one example](http://stackoverflow.com/questions/1106957/pass-array-by-reference-in-c/1106977#1106977). And congrats on actually doing at least *some* research on the subject, which is a far-cry more than almost anyone else does before posting questions about this subject. Well written question. – WhozCraig Jan 21 '13 at 19:28
  • Also note that K&R lacks plenty when it comes to good programming practice. When passing a string to a function that doesn't modify it, you should declare the parameter as `const char* s`. This is particularly important when a string literal is passed. Had your function attempted a write to `*s` you would invoke undefined behavior and the program could crash. – Lundin Jan 21 '13 at 19:55
  • Thanks everyone for making this into such a great thread! It will be difficult/impossible to pick an accepted answer. With your answers, I went back and read the part of the book that precedes this example. I think the key sentence that I didn't notice before was `By definition, the value of a variable of expression of type array is the address of element zero of the array`. So, when I use a string literal as a parameter in a function, I am not passing the string literal itself but the "type array", which is a pointer to the 0th index in the string literal, which is an array. – Dmitry Minkovsky Jan 21 '13 at 20:07
  • Thank you Lundin! I actually came across that when trying to answer this question myself before posting here. More about what you mention (using `const char *s` rather than `char *s`) can be found at https://www.securecoding.cert.org/confluence/display/seccode/STR05-C.+Use+pointers+to+const+when+referring+to+string+literals – Dmitry Minkovsky Jan 21 '13 at 20:12

6 Answers6

16

To understand how a string like "Hello World" is converted to a pointer, it is important to understand that, the string is actually hexadecimal data starting at an address and moving along till it finds a NULL

So that means, every string constant such as "Hello World" is stored in the memory somewhere

Possibility would be:

0x10203040 : 0x48 [H]
0x10203041 : 0x65 [e]
0x10203042 : 0x6C [l]
0x10203043 : 0x6C [l]
0x10203044 : 0x6F [o]
0x10203045 : 0x20 [' ']
0x10203046 : 0x57 [W]
0x10203047 : 0x6F [o]
0x10203048 : 0x72 [r]
0x10203049 : 0x6C [l]
0x1020304A : 0x64 [d]
0x1020304B : 0x00 [\0]

So, when this function is called with the above values in the memory, [left side is address followed by ':' and the right side is ascii value of the character]

int strlen(const char *s)
{
    int n;

    for (n = 0; *s != ′\0′; s++)
        n++;
    return n;
}

strlen("Hello World");

at that time, what gets passed to strlen is the value 0x10203040 which is the address of the first element of the character array.

Notice, the address is passed by value.. hence, strlen has its own copy of the address of "Hello World". starting from n = 0, following uptil I find \0 in the memory, I increment n and also the address in s(which then gets incremented to 0x10203041) and so on, until it finds \0 at the address 0x1020304B and returns the string length.

Aniket Inge
  • 25,375
  • 5
  • 50
  • 78
  • Thanks Aniket. Does changing the parameter signature to `const char *s` restrain this function, or any function with such a signature, from manipulating the pointer variable locally? Does the `const` essentially turn this pointer into an array? K&R point out that "one difference between an array name and a pointer must be kept in mind. A point is a variable, so pa=a and pa++ [where pa is a pointer] are legal. But an array name is not a variable; constructions like a=pa and a++ are illegal [where a is an array name]." – Dmitry Minkovsky Jan 21 '13 at 20:36
  • no, const only helps you to guard against accidentally modifying the contents of the array @dimadima. Arrays are internally treated as pointers, but pointers are not internally treated as arrays. An array name is a label to the start of an array. A subscript operator [i] dereferences the `i`th value in the array from the start of the array. – Aniket Inge Jan 21 '13 at 20:37
  • ****prints and puts on wall**** – Bitterblue Apr 14 '14 at 14:41
  • What do you mean by stored somewhere? is it stored in the stack or the code segment? – TheLogicGuy Dec 30 '16 at 16:16
3

"hello, world"

is an array of char (type is char[13]). The value of an array of char in an expression is a pointer to char. The pointer points to the first element of the array (i.e., the value of "hello, world" is &"hello, world"[0]).

ouah
  • 142,963
  • 15
  • 272
  • 331
1

Note that:

  • A pointer is (basically) a value pointing to a memory address.
  • A static string like "hello, word" is stored somewhere in memory

So, a pointer could as easily simply point to a static string as to any other (dynamical) structure that is stored in memory (like an array of characters). There is really no difference with the other provided examples.

Veger
  • 37,240
  • 11
  • 105
  • 116
1

Does the function assign this string literal as the value of its local variable *s and then use s as the array name/pointer?

Yes

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
sr01853
  • 6,043
  • 1
  • 19
  • 39
  • "Yes", in the sense that the string literal is an array. Since `by definition, the value of a variable of expression of type array is the address of element zero of the array`, the value of the array is the address of its first element. This first address is assigned to `s` as a local function variable. – Dmitry Minkovsky Jan 21 '13 at 20:30
1

As it says in the first paragraph of the same page (Page 99, K&R2):

"By definition, the value of a variable or expression of type array is the address of element zero of the array."

The value of "hello, world" would be the address of 'h'.

kong_yy
  • 11
  • 1
  • Or in other words: Literal strings in C are bytes delimited with `'\0'` and found via their address. So When you pass `"abc"` to a function ,you are actually passing the address (a `char *` pointer) to the function as parameter. Also string literals should be treated read-only in C. – U. Windl Sep 04 '19 at 00:15
0
char str[] = "Hello, world";
strlen(str);

string in C are array of characters with terminating NULL ('\0'), that mean it should be in the memory some where.

so what is the difference of sending a stored string as above and sending it directly as below

strlen("Hello, World");

The answer is both are same, but where the string is stored and how it's handled, here comes the compiler and stack.

The compiler at compile time pushes the string in to stack and send the starting address (char*) in the stack, the calling function sees a pointer and access the string.

The compiler also add codes after exist form the function to restore the stack in the correct place thus deleting the temporary string created enter image description here Note: the above is implementation dependent of the compiler, but most of the compiler works this way

Raj
  • 1,156
  • 11
  • 15