How to properly use pointers

I wanted to try something which was to have an array filled with strings, then use a pointer to print the strings one at a time to stdout. However, I keep encountering erros when I am trying to set the pointer equal to the array. Please help.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main ()
{
  //int one = 1;
  char names[][10]= {"one", "two", "three", "four", "five","six", "seven", "eight", "nine"};
  char **name_ptr;
  *name_ptr = names[0][10];

  for (int y = 0; y < 9; y ++)
  {
    printf("%s ", *name_ptr);
    name_ptr++;
  }
  printf("\n");
  return EXIT_SUCCESS;
}


Also while we're at it, what if I wanted to make the names to be 2D. Would something like this work? If not, how would I rewrite it?

char names[][10][10]= {"one", "two", "three", "four", "five","six", "seven", "eight", "nine"{"hundred"}};

And would a pointer also be the best idea to access it's elements or would just straight accessing the array elements be faster?
Last edited on
closed account (D80DSL3A)
For that name_ptr++ on line 11 to work it must increment to the next row of 10 chars, not just the next char.
A regular char* won't do.
You need a pointer to a row of 10 characters.
See below:
1
2
3
4
5
6
7
8
9
10
11
12
13
int main ()
{
  char names[][10]= {"one", "two", "three", "four", "five","six", "seven", "eight", "nine"};
  char (*name_ptr)[10] = names;// special pointer to row of 10 chars

  for (int y = 0; y < 9; y ++)
  {
    printf("%s ", *name_ptr);
    name_ptr++;// next row of 10 chars
  }
  printf("\n");
  return EXIT_SUCCESS;
}
Does that compile?

*name_ptr isn't the same type as *names. So incrementing both, won't give you the same result. Plus, *names is const and *name_ptr isn't.
Last edited on
You are confusing an array of arrays with a pointer to a pointer. The two are very different, and you cannot use a pointer to a pointer to point to a "straight" 2D array like the one you have.


ARRAY/POINTER MEMORY BASICS:

Arrays are stored consecutively in memory. A 1D char array will store each char next to each other. So it will look like this:

1
2
3
4
5
6
7
8
9
char example[10] = "one";

in memory (the _s are null characters):

one_______
^        ^
|        |
|        |
[0]     [9]


Note that there are exactly 10 chars (3 chars for the "one" text, followed by 7 null character). This is because the array is 10 chars big.

Now when you do a straight 2D array, you are taking that array of 10 chars and slapping a bunch of them back to back. So your 'names' array will look something like this in memory:

1
2
3
4
5
6
7
       [0][9]    [1][9]    [2][9]    [3][9]    [4][9]    [5][9]    [6][9]    [7][9]    [8][9]
         |         |         |         |         |         |         |         |         |
         v         v         v         v         v         v         v         v         v
one_______two_______three_____four______five______six_______seven_____eight_____nine______
^         ^         ^         ^         ^         ^         ^         ^         ^
|         |         |         |         |         |         |         |         |
[0][0]    [1][0]    [2][0]    [3][0]    [4][0]    [5][0]    [6][0]    [7][0]    [8][0]


You might notice that names[1][0] immediately follows names[0][9] in memory. This means that names[1][0] is the same variable as names[0][10]! It also means that names[2][0] is the same as names[0][20], and so on.

Using this, you can have a pointer move across the memory by incrementing it in steps of 10:

1
2
3
4
5
6
7
8
9
char* name_ptr;  // note:  not a pointer to a pointer (**)... just a regular pointer (*)

name_ptr = &names[0][0]; // point to the first char in the array

for (int y = 0; y < 9; y ++)
{
  printf("%s ", name_ptr);
  name_ptr += 10;
}


by adding 10 to name_ptr when it points to [0][0], we are making it point to [0][10] (which we previously established is the same memory as [1][0]).


This is different from pointer-to-pointer style arrays which I will illustrate in a bit...

Last edited on
@kbw, yes it compiles perfectly

$ g++ -Wall -Wextra -g -o Lett_C Count_letters.cc

$ ./Lett_C 
one two three four five six seven eight nine


Thank you!

@Disch

Thanks for your very detailed report, I am still reading it but I saw your solution and it looked very elegant

Btw, is there no reply button on this forum?
Last edited on
closed account (D80DSL3A)
@kbw. Yes, that compiles, runs and performs the desired action!
The version just above in Dischs post should work too.

@Disch. Great explanation.
Sorry I posted just minutes before you there.
Last edited on
It doesn't compile on gcc.
Pointer to pointer style 2D arrays work very differently than "straight" 2D arrays illustrated above. Straight 2D arrays are stored consecutively in memory, whereas pointer-to-pointer arrays are scattered throughout memory, with an EXTRA array of pointers to tell you where each item is.

Let's look at a typical p-to-p style array:

1
2
3
4
5
6
7
8
9
char** p = new char*[3];

p[0] = new char[10];
p[1] = new char[10];
p[2] = new char[10];

strcpy(p[0], "one");
strcpy(p[1], "two");
strcpy(p[2], "three");


Notice that there are 4 calls to new[] here (once for p, and then one for each p[0],p[1], and p[2]). This means we have 4 individual arrays. We do not have one giant array as we did above. These 4 individual arrays can (and likely will be) scattered across memory in an unpredictable fashion. So memory may look something like this:

1
2
3
4
5
6

.....two_______............one_______........002700050064.......three_____.
^    ^    ^    ^    ^    ^    ^    ^    ^    ^    ^    ^    ^    ^    ^    ^
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|   05    |   15    |   25    |   35    |   45    |   55    |   65    |   75
0        10        20        30        40        50        60        70


Here, the dots are unallocated memory (stuff we can't use / don't care about). Underscores are still null characters in the string, same as the previous example. But notice there's that clump of numbers at address 45. That's our 'p' array. It's an array of pointers, telling us where each of our other arrays are in memory.

For purposes of this example, I have shown each pointer as 4 digits: '0027', '0005' and '0064'. You'll notice that those represent the locations of the "one", "two", and "three" strings respectively.

Now to step through this array, we can use a pointer to a pointer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
char** name_ptr = p;  // same as name_ptr = &p[0].
    // name_ptr points to example address 0045.

printf("%s ", *name_ptr);
// here, *name_ptr uses the * dereference operator.  This will have the computer
//  look at the memory pointed to by name_ptr.
//  name_ptr points to address 0045.  If we read from address 0045, we get a value of 0027,
//  which is the location of the 'one' string.  Therefore this will print "one"

name_ptr++;  // by incrementing name_ptr, it now points to p[1].. or address 0049

printf("%s ", *name_ptr);
// same deal.  Computer will read from address 0049, getting a value of 0005... the location
//   of our 'two' string.  So this will print "two"


// ... and so on for the 3rd string 

Last edited on
Bah I thought I was the only one posting. I didn't see that like 3 other people had posted in the time I wrote those posts. Bah!

Oh well hopefully they help clarify.
Topic archived. No new replies allowed.