0

The program is expected to print each char of the string array.

#include <iostream>
#include <string>

using namespace std;
int main()
{
    const char* numbers[10]{"One", "Too",   "Three", "Four", "Five",
                "Six", "Seven", "Eight", "Nine", "Zero"};

    /*  This version did not work. Why?
           for (const char** ptr = numbers; *ptr != nullptr; *ptr++) {
                const char* pos = *ptr;
                while (*pos != '\0')
                    cout << *(pos++) << " ";
            }
    */
    for(unsigned int i = 0; i < sizeof(numbers) / sizeof(numbers[0]); ++i)
    {
        const char* pos = numbers[i];
        while(*pos != '\0')
            printf("%c ", *(pos++));
        printf("\n");
    }
    return 0;
}

I am aware that my code is a mixture of C++17 and C(in a transition from C to C++, nullptr, cout are two examples), but not sure the first for-loop with

for (const char** ptr = numbers; *ptr != nullptr; *ptr++)

is correct or not. What's wrong with it? Is there a "best practice" to looping thru array of string(char array , not string object yet), especially with the double pointer I'd like to catch, in this case? Thanks!

Ghasem Ramezani
  • 2,683
  • 1
  • 13
  • 32
Yifangt
  • 151
  • 1
  • 10
  • Consider putting together a [mcve] that actually compiles. – Retired Ninja Sep 11 '21 at 05:08
  • Thanks! You are really fast! Post has been edited with full code. – Yifangt Sep 11 '21 at 05:18
  • Arrays have length, they are not ended by any marker such as NULL or alike. Add an approriate ending marker by yourself. – Jean-Baptiste Yunès Sep 11 '21 at 05:29
  • 1
    The term "double pointer" is ambiguous, and most accurately refers to type `double*`. I suggest using the term "pointer to pointer" instead (as suggested by the [pointer-to-pointer](https://stackoverflow.com/questions/tagged/pointer-to-pointer) tag description). – Keith Thompson Sep 11 '21 at 08:48
  • I read comments about "pointer-to-pointer" in other places too. I'll try to use as suggested. – Yifangt Sep 11 '21 at 14:58

3 Answers3

3

Two things -

First, in this loop expression, you don't need to dereference the ptr after incrementing it - *ptr++.

for (const char** ptr = numbers; *ptr != nullptr; *ptr++)
                                                  ^^

*ptr++ will be grouped as - *(ptr++), which means, (post)increment the ptr and dereference the result of (post)increment. It should be just ptr++, as we need the ptr pointer to point to next element in the numbers array after executing the loop body.

Second, if your loop condition is checking for nullptr then the array, which loop is iterating, should have nullptr as a marker to indicate the end of array and you need to increase the size of array as well to adjust end marker:

     const char* numbers[11] {"One", "Too", "Three", "Four", "Five",
                              "Six", "Seven", "Eight", "Nine", "Zero", nullptr};

With the above mentioned changes, the following loop should print the numbers array strings:

       for (const char** ptr = numbers; *ptr != nullptr; ptr++) {
           const char* pos = *ptr;

           while (*pos != '\0')
               cout << *(pos++) << " ";

           cout << "\n";
       }

Since, you have added a new element in the numbers array to mark end of array, be cautious, in the second loop, you are doing sizeof(numbers)/sizeof(numbers[0]) to get the array size and it will give 11 and second loop will end up accessing the nullptr which will be undefined behaviour. Either subtract 1 from sizeof result in loop condition or add a check pos != nullptr before processing it.

H.S.
  • 11,654
  • 2
  • 15
  • 32
0

In your first loop you a looking for ‘nullptr’ in your array, but you didn’t put it there.

You are reading uninitialized garbage after you array.

I suggest to use std::vector or std::array

Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27
  • Thanks for pointing out 'nullptr' not in the array. Added NULL to the array, for( const char** p2 = numbers; *p2 != NULL; *p2++) { ...} still segfault. – Yifangt Sep 11 '21 at 07:10
0

Try these edits and see what happens

const char* numbers[11]{"One", "Too", "Three", "Four", "Five", 
                                    "Six", "Seven", "Eight", "Nine", "Zero", NULL};

and

;i < sizeof(numbers)/sizeof(numbers[0])-1;

in the second for loop

Basically *ptr points to the beginning of the respective string. But after last one, it goes out-of-bound. If you really have to compare to nullptr the above is the way to do.

EDIT

Yeah, in addition to the above, ptr should be incremented instead of *ptr. *ptr will be traversing over the string rather than that array.

mr.loop
  • 818
  • 6
  • 20
  • The pure C part is working. But my question is about the for-loop part with double pointer that I am struggling with. – Yifangt Sep 11 '21 at 07:04
  • @Yifangt Did you tried with the edits ? The `-1` after `sizeof` will not change anything. It is there because there is 1 extra element in the array now. – mr.loop Sep 11 '21 at 08:14
  • Yes, I tried the -1 for the commented part. Still segfault. I think the problem is with the *ptr++ in the for loop, cf answer by H.S. Thanks anyway. – Yifangt Sep 11 '21 at 08:40
  • @Yifangt Yeah I missed that. Also, -1 is not for the commented loop but the second loop – mr.loop Sep 11 '21 at 09:11