9

I have written this code which is simple

#include <stdio.h>
#include <string.h>

void printLastLetter(char **str)
{
    printf("%c\n",*(*str + strlen(*str) - 1));
    printf("%c\n",**(str + strlen(*str) - 1));
}

int main()
{
    char *str = "1234556";
    printLastLetter(&str);
    return 1;
}

Now, if I want to print the last char in a string I know the first line of printLastLetter is the right line of code. What I don't fully understand is what the difference is between *str and **str. The first one is an array of characters, and the second?? Also, what is the difference in memory allocation between char *str and str[10]? Thnks

amahmud
  • 434
  • 4
  • 14
yotamoo
  • 5,334
  • 13
  • 49
  • 61

8 Answers8

21

char* is a pointer to char, char ** is a pointer to a pointer to char.

char *ptr; does NOT allocate memory for characters, it allocates memory for a pointer to char.

char arr[10]; allocates 10 characters and arr holds the address of the first character. (though arr is NOT a pointer (not char *) but of type char[10])

For demonstration: char *str = "1234556"; is like:

char *str;         // allocate a space for char pointer on the stack
str = "1234556";   // assign the address of the string literal "1234556" to str

As @Oli Charlesworth commented, if you use a pointer to a constant string, such as in the above example, you should declare the pointer as const - const char *str = "1234556"; so if you try to modify it, which is not allowed, you will get a compile-time error and not a run-time access violation error, such as segmentation fault. If you're not familiar with that, please look here.

Also see the explanation in the FAQ of newsgroup comp.lang.c.

Community
  • 1
  • 1
MByD
  • 135,866
  • 28
  • 264
  • 277
  • what happens in the memory if i write char*ptr = "HELLO"? – yotamoo Aug 15 '11 at 13:18
  • I think that was me! As I was scrolling I saw the arrow flash orange. It was a mistake. I've only been here a few days. I have given an up arrow to cancel that out but I now see that was also a mistake and I should have double pressed the down arrow to toggle it. – QuentinUK Aug 15 '11 at 14:25
  • For perfection, your answer should perhaps mention that non-const pointers should not be used to point at string literals. – Oliver Charlesworth Aug 15 '11 at 14:31
  • @Oli Charlesworth - there's always more to add, but that's an important note. Will edit in a few min. – MByD Aug 15 '11 at 14:32
  • With `char arr[10]`, `arr` does not "hold" the address; rather, it is implicitly converted into a pointer in a variety of perhaps-unexpected ways. `char* ptr = "HELLO"` will work basically the same as `char *ptr; ptr = "HELLO"` as in the answer, except that the pointer is initialized to point at the string literal instead of being assigned afterward. In either case, the string literal is put somewhere 'safe' at the program startup; usually, the text actually appears verbatim within the executable (not inside the actual code part) so it gets copied to memory by the OS like everything else. – Karl Knechtel Aug 15 '11 at 14:42
  • @Karl Knechtel - away from home - thanks for the comment. feel free to edit the answer if you feel like it. – MByD Aug 15 '11 at 14:46
15

char **x is a pointer to a pointer, which is useful when you want to modify an existing pointer outside of its scope (say, within a function call).

This is important because C is pass by copy, so to modify a pointer within another function, you have to pass the address of the pointer and use a pointer to the pointer like so:

void modify(char **s)
{
  free(*s); // free the old array
  *s = malloc(10); // allocate a new array of 10 chars
}

int main()
{
  char *s = malloc(5); // s points to an array of 5 chars
  modify(&s); // s now points to a new array of 10 chars
  free(s);
}

You can also use char ** to store an array of strings. However, if you dynamically allocate everything, remember to keep track of how long the array of strings is so you can loop through each element and free it.

As for your last question, char *str; simply declares a pointer with no memory allocated to it, whereas char str[10]; allocates an array of 10 chars on the local stack. The local array will disappear once it goes out of scope though, which is why if you want to return a string from a function, you want to use a pointer with dynamically allocated (malloc'd) memory.

Also, char *str = "Some string constant"; is also a pointer to a string constant. String constants are stored in the global data section of your compiled program and can't be modified. You don't have to allocate memory for them because they're compiled/hardcoded into your program, so they already take up memory.

James O'Doherty
  • 2,186
  • 13
  • 14
2

The first one is an array of characters, and the second??

The second is a pointer to your array. Since you pass the adress of str and not the pointer (str) itself you need this to derefence.

printLastLetter( str ); 

and

printf("%c\n",*(str + strlen(str) - 1)); 

makes more sense unless you need to change the value of str.

stacker
  • 68,052
  • 28
  • 140
  • 210
  • @cnicutar No , consider a string of length 2 e.g "AB" strlen would return 2, 2 - 1 is one, which would be the offset to the last char in the string "AB": – stacker Aug 15 '11 at 13:29
2

You might care to study this minor variation of your program (the function printLastLetter() is unchanged except that it is made static), and work out why the output is:

3
X

The output is fully deterministic - but only because I carefully set up the list variable so that it would be deterministic.

#include <stdio.h>
#include <string.h>

static void printLastLetter(char **str)
{
    printf("%c\n", *(*str + strlen(*str) - 1));
    printf("%c\n", **(str + strlen(*str) - 1));
}

int main(void)
{
    char *list[] = { "123", "abc", "XYZ" };
    printLastLetter(list);
    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

char** is for a string of strings basically - an array of character arrays. If you want to pass multiple character array arguments you can use this assuming they're allocated correctly.

char **x; *x would dereference and give you the first character array allocated in x. **x would dereference that character array giving you the first character in the array.

John Humphreys
  • 37,047
  • 37
  • 155
  • 255
0

for your code snippet, *str holds address to a char and **str holds address to a variable holding address of a char. In another word, pointer to pointer.

Whenever, you have *str, only enough memory is allocated to hold a pointer type variable(4 byte on a 32 bit machine). With str[10], memory is already allocated for 10 char.

Shamim Hafiz - MSFT
  • 21,454
  • 43
  • 116
  • 176
0

**str is nothing else than (*str)[0] and the difference between *str and str[10] (in the declaration, I assume) I think is, that the former is just a pointer pointing to a constant string literal that may be stored somewhere in global static memory, whereas the latter allocates 10 byte of memory on the stack where the literal is stored into.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
0

char * is a pointer to a memory location. for char * str="123456"; this is the first character of a string. The "" are just a convenient way of entering an array of character values. str[10] is a way of reserving 10 characters in memory without saying what they are.(nb Since the last character is a NULL this can actually only hold 9 letters. When a function takes a * parameter you can use a [] parameter but not the other way round.

You are making it unnecessarily complicated by taking the address of str before using it as a parameter. In C you often pass the address of an object to a function because it is a lot faster then passing the whole object. But since it is already a pointer you do not make the function any better by passing a pointer to a pointer. Assuming you do not want to change the pointer to point to a different string.

QuentinUK
  • 2,997
  • 21
  • 20