1

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?

4
  • stackoverflow.com/questions/581657/… This might help you understand the pointers a bit more clearly. Commented May 31, 2017 at 3:09
  • 1
    *sp1[3] is an array of pointers to char, (*sp2)[5] is a pointer to array 5 of type char, sp3[][5] is a 2D array (array of arrays char[5]). Note:, in each of the last two cases you invoke undefined behavior when you fail to provide adequate storage for, e.g. "this 2" (which is 6-chars + 1-char for the nul-terminating char). Your 5 needs to be, at minimum, 7. Commented May 31, 2017 at 3:15
  • 2
    char c declares c as an uninitialized character. *p = &c creates p as a pointer to char (there is only 1-char of storage), p++; causes p to point outside of the storage allocated for c, any attempt to dereference p invokes undefined behavior. Commented May 31, 2017 at 3:21
  • "In this function lineptr is the name of an array" -- well yes and no. lineptr may have been an array of pointers each to the beginning of one of nlines lines, but when passed as a parameter to a function, the array is converted to a pointer, so what you actually have in the function is a pointer to pointer to char or char ** which you can easily increment. (had it been a 2D array, the parameter would have been char (*lineptr)[WIDTH], int nlines...) Commented May 31, 2017 at 4:53

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much. This is the first time I ask on "stackoverflow",I am astonished by you passion and professional answer, I learn a lot including many minutiae which I didn't realize before.Thanks sincerely.
Glad to help. C is probably one of the most elegant and flexible languages you can learn. It gives you bit-level control over memory, but it requires that you measure and account for the memory you use. C will make you a better programmer no matter what language you choose, because you will have learned how to account for, and manage memory at the byte and bit level. Good luck with your coding.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.