5

I read that:

char a[] = "string"; 

is a: "string"

whereas

char *ptr = "string" 

is ptr: [__] ---> "string"

I am little confused. One thing I know is that pointers always store the address. In case of character pointer what address does it store? What does this block represent (block which I made pointing to string). Is it the starting address of the "string".

And in case of array? How can I clearly differentiate between char pointer and char array?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 2
    http://stackoverflow.com/questions/7564033/difference-between-char-and-char possible duplicate? – Josh Engelsma Sep 10 '14 at 00:46
  • @JoshEngelsma please remove the duplicate tag. Once its answered put it back. I saw that question but it still doesn't clearly answers my question. what address ptr stores? – Stack Overflow 32 Sep 10 '14 at 01:03
  • 2
    @JoshEngelsma: I don't much like C++ questions as duplicates for C questions. Granted, the technology is the same in this case, but it is still preferable to find a C question as a duplicate for a C question. – Jonathan Leffler Sep 10 '14 at 01:47
  • You might find [How is memory allocated for an implicitly defined multidimensional array in C99?](http://stackoverflow.com/a/13850748/15168) of help (it has diagrams to help explain), or you might find the multidimensional code too much (though you'll need to understand it eventually — but maybe not this week). – Jonathan Leffler Sep 10 '14 at 01:49
  • @JonathanLeffler i understand multidimentional arrays a[][5] , (a*)[5] but its just sometimes get confused in very basic stuff...i try to understand every bit of whats happening under to hood – Stack Overflow 32 Sep 10 '14 at 01:59

7 Answers7

6

Diagrams may help.

char *ptr = "string";

+-------+          +----------------------------+
|  ptr  |--------->| s | t | r | i | n | g | \0 |
+-------+          +----------------------------+

char a[] = "string";

+----------------------------+
| s | t | r | i | n | g | \0 |
+----------------------------+

Here, ptr is a variable that holds a pointer to some (constant) data. You can subsequently change the memory address that it points at by assigning a new value to ptr, such as ptr = "alternative"; — but you cannot legitimately change the contents of the array holding "string" (it is officially readonly or const, and trying to modify it may well crash your program, or otherwise break things unexpectedly).

By contrast, a is the constant address of the first byte of the 7 bytes of data that is initialized with the value "string". I've not shown any storage for the address because, unlike a pointer variable, there isn't a piece of changeable storage that holds the address. You cannot change the memory address that a points to; it always points to the same space. But you can change the contents of the array (for example, strcpy(a, "select");).

When you call a function, the difference disappears:

if (strcmp(ptr, a) == 0)
    …string is equal to string…

The strcmp() function takes two pointers to constant char data (so it doesn't modify what it is given to scrutinize), and both ptr and a are passed as pointer values. There's a strong case for saying that only pointers are passed to functions — never arrays — even if the function is written using array notation.

Nevertheless, and this is crucial, arrays (outside of paramter lists) are not pointers. Amongst other reasons for asserting that:

  • sizeof(a) == 7
  • sizeof(ptr) == 8 (for 64-bit) or sizeof(ptr) == 4 (32-bit).
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • but if calculate strlen(pointer) then why it would show me 3 for "foo" i guess it doesn't contain '\0' whereas in case of strlen(array) its 4 including '\0' at the end? – Stack Overflow 32 Sep 10 '14 at 02:13
  • 2
    The value returned by `strlen()` is the number of (non-null) bytes starting at the pointer it is passed and excluding the terminal `'\0'`. The value returned by `sizeof(array)` or `sizeof("string")` is the storage used by the array or string, and that _does_ include the trailing `'\0'` at the end of a string literal. – Jonathan Leffler Sep 10 '14 at 02:35
3

In case of character pointer what address does it store? What does this block represent (block which I made pointing to string). Is it the starting address of the "string".

This blocks represents a WORD or DWORD (achitecture dependant), the content of this block is a memory address, a random location defined at compile time. That memory address is the address of first character of the string.

In practice, the difference is how much stack memory it uses.

For example when programming for microcontrollers where very little memory for the stack is allocated, makes a big difference.

char a[] = "string"; // the compiler puts {'s','t','r','i','n','g', 0} onto STACK 

char *b = "string"; // the compiler puts just the pointer onto STACK 
                    // and {'s','t','r','i','n','g',0} in static memory area.

Maybe this will help you understand.

assert(a[0] == 's'); // no error.
assert(b[0] == 's'); // no error.
assert(*b == 's');   // no error.
b++; // increment the memory address, so points to 't'
assert(*b == 's');   // assertion failed
assert(*b == 't');   // no error.
rnrneverdies
  • 15,243
  • 9
  • 65
  • 95
  • i know that a[] = actually fills "string" onto the position and in case of *a it just points to some random "string" in memory. but my question is in case of char *a,,,,a is what ? does a = starting address which is pointing to string? if yes what is diff b/w pointer and arrays.............in both the cased: char arr[] ,,, arr is the address....also char *arr ,,,,,,arr its address of "string" – Stack Overflow 32 Sep 10 '14 at 01:28
2

char a[] = "string"; initializes the value of the array of chars called a with the value string. And the size of a.

char *a = "string"; creates an unnamed static array of chars somewhere in memory and return the address of the first element of this unnamed array to a.

In the first one, a stores the address of the first element of the array. So when we index something like a[4], this means 'take' the 4th element after the begin of the object named a.

In the second, a[4] means 'take' the 4th element after the object that a points to.

And for your last question:

A char array is a 'block' of contiguous elements of type char. A char pointer is a reference to an element of the type char.

Due to pointer arithmetics, a pointer can be used to simulate (and access) an array.

Maybe those 3 links help make the difference more clear:

http://c-faq.com/decl/strlitinit.html

http://c-faq.com/aryptr/aryptr2.html

http://c-faq.com/aryptr/aryptrequiv.html

braindf
  • 734
  • 4
  • 14
1

You may find it useful to think of:

char * a = "string";

as the same as:

char SomeHiddenNameYouWillNeverKnowOrSee[] = "string";   /*  may be in ReadOnly memory! */
char * a = &SomeHiddenNameYouWillNeverKnowOrSee[0];
John Hascall
  • 9,176
  • 6
  • 48
  • 72
1

Did you ever tried to open some executabe file with a text editor ? It appears merely as garbage, but in the middle of the garbage you can see some readable strings. These are all the litteral strings defined in you program.

printf("my literal text");
char * c = "another literal text"; // should be const char *, see below

If your program contains the above code you may be able to find my literal textand another literal text in program's binary (actually it depends on the details of the binary format, but it often works). If you are Linux/Unix user you can also use the strings command for that.

By the way, if you write the above code, C++ compilers will emit some warning (g++ say: warning: deprecated conversion from string constant to ‘char*’ because such strings are not of type char * but const char [] (const char array) which decay to const char * when assigned to a pointer.

This also is the case with C compilers, but the above error is so very common that this warning is usually disabled. gcc does not even include in -Wall, you have to explicitely enable it through -Wwrite-strings. The warning is warning: initialization discards ‘const’ qualifier from pointer target type.

It merely reminds that you are theoretically not allowed to change the literal texts through pointers.

The executable may loads such strings in a read only part of Data segment memory. If you try to change the content of string it can raise a memory error. Also the compiler is allowed to optimise literal text storage by merging identical strings for instance. The pointer just contains the address in (read only) memory where the literal strings will be loaded.

On the other hand

char c[] = "string"; is mere syntaxic sugar for char c[7] = {'s', 't', 'r', 'i', 'n', 'g', 0}; If you do sizeof(c) in your code it will be 7 bytes (the size of the array, not the size of a pointer). This is an array on stack with an initialiser. Internally the compiler can do wathever it likes to initialize the array. It can be characters constants loaded one by one in the array, or it can involved a memcpy of some hiden string literal. The thing is that you have no way to tell the difference from your program and find out where the data comes from. Only the result matters.

By the way a thing that is slightly confusing is that if you define some function parameter of the type char c[], then it won't be an array but an alternative syntax for char * c.

kriss
  • 23,497
  • 17
  • 97
  • 116
0

In your example, ptr contains the address of the first char in the string.

As for the difference between a char array and a string, in C terms there is no difference other than the fact that by convention what we call "string" is a char array where the final char is a NULL, to terminate the string.

i.e. even if we have an array of char with 256 potential elements, if the first (0th) char is null (0) then the length of the string is 0.

Consider a variable str which is a char array of 5 chars, containing the string 'foo'.

*ptr  =>   str[0]   'f'
           str[1]   'o'
           str[2]   'o'
           str[3]   \0
           str[4]   ..

A char *ptr to this array would reference the first element (index = 0) and the 4th element (index = 3) would be null, marking the end of the 'string'. The 5th element (index = 4) will be ignored by string handling routines which respect the null terminator.

Deltics
  • 22,162
  • 2
  • 42
  • 70
  • but if calculate strlen(ptr) then why it would show me 3 for "foo" i guess it doesn't contain '\0' whereas in case of strlen(arr) its 4 including '\0' at the end? @Deltics – Stack Overflow 32 Sep 10 '14 at 02:12
  • strlen never counts the trailing '\0', if you have a string only containing '\0' it's strlen will be 0. – kriss Sep 10 '14 at 02:32
  • @StackOverflow32, exactly right. A null terminate string of length 3 occupies 4 chars, 3 for the string +1 for the \0. For the purposes of considering the "length" of a string, the \0 terminator is not deemed to be "part" of the string itself, it only marks the end of it. Just as when you count the number of words in a sentence, you don't count the period at the end. :) – Deltics Sep 10 '14 at 20:43
  • @StackOverflow32 if you are still coming to grips with null terminated strings, then this might be too advanced voodoo for you, but you should also bear in mind that for anything other than ASCII strings, the number of **characters** in a string does not necessarily == the number of **bytes** and the terminator may be a 2-byte null (\0\0) or even a 4-byte null (\0\0\0\0). – Deltics Sep 10 '14 at 20:47
  • @Deltics were can i read about 2 byte & 4 byte null characters – Stack Overflow 32 Sep 13 '14 at 23:23
-1

If you are asking what a contains in each case then:

char a[] = "string";
// a is a pointer. 
// It contains the address of the first element of the array.

char *a = "string";
// Once again a is a pointer containing address of first element.

As rnrneverdies has explained in his answer, the difference is in where the elements are stored.

Chronos
  • 91
  • 1
  • 12