jacktown
jacktown

Reputation: 35

Detailed difference between pointer and array

Below is the code in C:

void test1(void);

int main(){
    test1();
    return 0;
}

void test1(void){
    char c,
        *p = &c,
        *sp1[3] = {"this 1","this 2", "this 3"},    //pointers array
        (*sp2)[5] = {"this 1","this 2", "this 3"},  
        //2 dimensions array declaration in method 1 
        sp3[][5] = {"this 1","this 2", "this 3"};   
        //2 dimensions array declaration in method 2

    p++;    //ok 
    sp1++;  //error 
    sp2++;  //ok
    sp3++;  //error     
}

I've read that a pointer is a variable, so increment is ok for it, but an array name is not a variable, so assignment is not acceptable.

In the code above, p is a pointer, so an increment is right; sp1, sp3 are both array names and increment causes errors, but why is it ok for sp2?

In the same book, there is a function as below:

//print lines 
void writelines(char *lineptr[],int nlines){
    while(--nlines >= 0){
        printf("%s\n",*lineptr++);
    }
}

In this function lineptr is the name of an array, but an increment is applied on it. Why? Is it because the parameter is converted by value in C, so lineptr is actually a pointer?

Upvotes: 1

Views: 93

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84531

It is unclear what you code is attempting to accomplish other than simply wrestling with pointers and arrays to try and wrap your head around their use (which is an excellent use of your C learning time).

With that in mind, let's look at your declarations and try and help make sense out of them. First let's look at c and p (I have initialized 'c' for you to avoid working with an uninitialized value):

    char c = 'a',
        *p = &c,

c is simply declared as a char with automatic storage for 1-char created on the function stack. p is declared as a character pointer (or pointer to char) and its value is initialized to the address of c

(a pointer is simply a variable that holds the address of something else as its value. a normal variable, e.g. c holds an immediate-value, 'a' in this case. p simply holds the address of c as its value, e.g. p points to c)

You next declare an array of pointers that are initialized to hold the addresses of the string literals provided in the initializer, e.g.

        *sp1[] = {"this 1","this 2", "this 3"},

note: you do not need to specify 3 if you are providing initialization of each of the pointers.

Here you effectively declare an array of 3-pointers to char *. Where sp1[0] points to "this 1", sp1[1] points to "this 2", etc...

Next you declare a pointer to an array 5 char (or pointer to an array of 5-chars) Note: as in my comment, that is insufficient by 2-chars, so it is declared as a pointer to an array of 7-chars below. Now here is where you need to take care. Since you declare a pointer to an array it itself does not have any storage allocated for 7-chars, (it is just a pointer to something that already holds 7-chars). You have a few options.

Since sp3 is of type char[][7], you can declare sp2 after sp3 and assign it the address of a compatible array, e.g.

    *sp1[] = {"this 1","this 2", "this 3"},
    sp3[][7] = {"this 1","this 2", "this 3"},
    (*sp2)[7] = sp3,  

to have sp2 point to the beginning of sp3, or you can create storage for the literals following your sp2 declaration by using the C99 compound literal, e.g.

        *sp1[] = {"this 1","this 2", "this 3"},
        /* using a compound literal to create storage */
        (*sp2)[7] = (char [][7]){"this 1","this 2", "this 3"},  
        sp3[][7] = {"this 1","this 2", "this 3"},

And finally, you can dynamically allocate storage for sp2 (which we will leave for another time). Now since you are just wrestling with pointers here, you see you cannot simply increment sp3 it is an array, but... you can declare a pointer to its beginning and increment that as part of your exercise, e.g.

        sp3[][7] = {"this 1","this 2", "this 3"},
        *p3 = *sp3; /* pointer to first element in sp3 */

Now putting all the pieces of the puzzle together and exercising the increment of each of your pointers, you can do something similar to the following. (note: I do not derefernce the value of p after incrementing p++, instead I derefernce p - 1 so that it still points to valid storage)

#include <stdio.h>

void test1 (void);

int main (void) {
    test1();
    return 0;
}

void test1 (void) {
    char c = 'a',
        *p = &c,
        *sp1[] = {"this 1","this 2", "this 3"},
        /* using a compound literal to create storage */
        (*sp2)[7] = (char [][7]){"this 1","this 2", "this 3"},  
        sp3[][7] = {"this 1","this 2", "this 3"},
        *p3 = *sp3; /* pointer to first element in sp3 */

    p++;        /* advance p to one-char-past-c     */
    (*sp1)++;   /* advance pointer to sp1[0] by one */
    sp2++;      /* advance pointer to next char[7]  */
    p3++;       /* advance pointer to sp3[0] by one */

    printf ("(p - 1): %c\n*sp1: %s\n*sp2: %s\np3  : %s\n",
            *(p - 1), *sp1, *sp2, p3);
}

Example Use/Output

$ ./bin/arrayptrinc
(p - 1): a
*sp1: his 1
*sp2: this 2
p3  : his 1

Note: the output is the same if you chose to declare sp2 after sp3 and have sp2 point to the beginning of sp3 with:

    char c = 'a',
        *p = &c,
        *sp1[] = {"this 1","this 2", "this 3"},
        sp3[][7] = {"this 1","this 2", "this 3"},
        (*sp2)[7] = sp3,  
        *p3 = *sp3; /* pointer to first element in sp3 */

While I'm not sure this is exactly what you had in mind, I think it is close to where you were going with your exercise. If not, let me know. Look things over and let me know if you have any further questions.

Upvotes: 2

Related Questions