tags:

views:

697

answers:

5

I am practicing using pointers.

I have a pointer to an array of 3 strings: "dog", "cat", "rat".

I can print the contents using a for loop and using an array.

However, I am having problems printing them using pointer arithmetic. I would like to increment the pointer to the next element in the array. However, all it does is print the dog letters.

Code:

int main(int argc, char **argv)
{
    char *str[3] = { "DOG", "CAT", "RAT"};
    int i = 0;

    /* display using an array element */
    for(i = 0; i < 3; i++)
    {
 printf("str: %s\n", str[i]);
    }

    /* display using a pointer arthimatic */
    while((*str)++)
    {
 printf("str: %s\n", str);
    }

    getchar();

    return 0;
}

How can I accomplish this?

Edit:

Code:

while(str)
{
 printf("str: %s\n", *(str++));
}

However, I get this error message. Doesn't the I-value have to be a variable of some sort?

error C2105: '++' needs l-value

+1  A: 

The problem with your code is that you're incrementing the dereferenced pointer str, which gives you a char * to the first element in the array (ie, dog).

You should be incrementing str itself, not what it points to.

However your loop termination check won't work in that case as there is no element in the array at the moment for which str == 0 holds true. In order to get that to work, you'll need to add a fourth element to the array that is 0.

Timo Geusch
+1  A: 
(*str)++

Increments the value pointed to by s. You will need to increment the pointer itself and print the value of the pointee. Note, that str is not a l-value and you cannot increment it either.

Also, if you increment first, then you are left with only two legal strings that you can print. You invoke UB after that.

Try this:

int main(void)
{
    /* we have added a sentinel to mark the end of the array */
    char *str[] = { "DOG", "CAT", "RAT", 0 };
    /* since str is an array, you cannot use it to loop, have a walker */
    char **w = str;

    /* display using a pointer arthimatic */
    while(*w)
    {
        printf("str: %s\n", *w++);
    }


    return 0;
}

Look up operator precedence and binding in C.

dirkgently
A: 
while((*str)++)    
{        printf("str: %s\n", str);    }

This increments *str which is the letter 'd'. You don't want to do that. You want to increment the pointer. This code should do what you want:

while((str)++)    
{        printf("str: %s\n", str);    }
Steve Rowe
str is the name of an array. It cannot be incremented.
RBerteig
+7  A: 

You first have to get a pointer, and you would need a condition when to stop. A last NULL pointer can be used for that. So the code becomes

char *str[] = { "DOG", "CAT", "RAT", NULL };
char **elem_p = str;

/* display using a pointer arthimatic */
while(*elem_p) {
    printf("str: %s\n", *elem_p);
    elem_p++;
}

What you did was to increment the pointer stored in the array's first element. That pointer will never too soon equal to a null pointer (if at all), So, the loop will not stop until that pointers' internal value overflows or something else happens so that it equals to a null pointer. Then, you pass a pointer to the arrays first element to printf (you pass the array, but the compiler will convert it to a pointer - see below). Printf will interpret the bytes of those pointers as characters and print them, which will result in garbage printed out if it doesn't crash right away.

You want to increment at a higher level instead: Increment not one element (pointer) of the array, but the pointer to the elements itself. Now, you can't do

str++

Because str is an array. It's not a pointer, even though it can be converted to a pointer, which will then point to the first element of it. So, we create a pointer which points to str[0] initially, but increment it all again. Note that we increment it after printing, so that we print out the first element too.

Actually, i think i should explain why you can't do str++. Well, str is an array. An array is an object that occupies some fixed amount of storage. Above, the array occupies 4 times the size of a char pointer, 4 * sizeof(char*). What looks like a pointer at the first glance is a block of elements of the same type. For addressing elements, the compiler can make up a pointer out of an array in expressions, which then can be used to address elements in the array. If you do str++, the compiler will create a pointer for you. But that pointer is temporary, exists only for a short while for the sole purpose of immediately doing something with it, but it can not be changed like being incremented. That is the reason that we create a real pointer variable that we then can increment.

Johannes Schaub - litb
char *str[3] = { "DOG", "CAT", "RAT", NULL }; Here I get an error "too many initializes' Should I change the element to *str[4]?
robUK
oops, yeah please :) best just leave it empty. the array size will be calculated automatically.
Johannes Schaub - litb
i misread your code. i thought you did printf("str: %s\n", *str); which would have printed OG, G, and so on. now with only str, i would expect it print garbage (because it would interpret the pointers as characters).
Johannes Schaub - litb
Hello, what is the difference between char *animals[] = {"dog", "cat", 0}; and int numbers[] = {1, 2, 3}; Why do I need the * for char. And I don't need it for int? With *animals[]. I am creating 1 pointer that will pointer to a number of different elements in an array? Thanks
robUK
fixed the answer. robUK, no the * is because the arrays' elements are pointers. see where you need it to: int a, b; int *array[] = {
Johannes Schaub - litb
robUK, the "*" binds to the element type, not to the identifier. so it is the same as typedef char* char_ptr; char_ptr animals[] = { "dog", "cat", 0 };
Johannes Schaub - litb
precedence of operator[] and operator*. char *p[] is read as declaring p as an "array of ...". to make a "pointer to array of..." you do char (*p)[] . but that does not make sense in your code. it is useful in multi dimensional arrays. but i suspect it's more confusing than helpful at this time.
Johannes Schaub - litb
+1  A: 

str, being an array, cannot be incremented.

Right now, you're incrementing (*str), which is str[0]: the first element of that array. Since this element is a pointer, you're incrementing the pointer, making it reference the subsequent elements of the string "DOG".

What you need is a pointer that can point to (and thus walk over) str's elements. Since the elements are char*, the pointer to them would be char** - a double pointer.

aib