5

The following program in C++ prints more output than I expected. Can anyone explain why this has happened? The program attempts to use pointers to loop through the integer array, printing each value along the way.

#include <cstdio>
using namespace std;

int main(int argc, char **argv) {
    puts("hi");
    int ia[5] = {1,2,3,4,5};
    for (int *p = ia; *p; ++p) {
        printf("Char is: %d\n", *p);
    }
    return 0;
}

/*
 hi
 Char is: 1
 Char is: 2
 Char is: 3
 Char is: 4
 Char is: 5
 Char is: 32767
 Char is: -811990796
 Char is: -133728064
 Char is: 1606416320
 Char is: 32767
 Char is: -1052593579
 Char is: 32767
 Program ended with exit code: 0
*/
7
  • 1
    Your loop is written to stop when it encounters a zero element in the array (whereupon *p is evaluated to false). But your array does not in fact contain a zero element. So the loop walks off the end of the array, therefore exhibiting undefined behavior. Commented Jan 17, 2017 at 2:04
  • FWIW, this is not c++ except for: completely irrelevant using namespace std, and an alias for stdio.h. ideone.com/saAZKk Commented Jan 17, 2017 at 2:17
  • @luk It is entirely valid C++ code. Commented Jan 17, 2017 at 2:24
  • @latedeveloper Any C code is perfectly valid C++ code. Does that mean we could drop c tag? Let me ask another way, what in this problem is c++ specific? EDIT: Sorry, let's not go into a debate please. I just wanted to point out, this is not really c++ specific and make people reevaluate whether this is C or C++. Too many people confuse this. Commented Jan 17, 2017 at 2:34
  • 1
    @luk "Any C code is perfectly valid C++ code" - no, it isn't. The OP's code is. Commented Jan 17, 2017 at 2:51

4 Answers 4

21

You will need to have a 0/NULL value to stop at, currently you do not.

Your loop condition will allow iteration until you get a value that evaluates to false (i.e 0) and your array does not contain that, so your iteration will continue on past the bounds of the array and will at some point exit when it access some memory its not supposed to.

There are several ways to fix it. You can add a 0 to the end of the array.

#include <cstdio>
using namespace std;

int main(int argc, char **argv) {
    puts("hi");
    int ia[] = {1,2,3,4,5, 0};
    for (int *p = ia; *p; ++p) {
        printf("Char is: %d\n", *p);
    }
    return 0;
}

Issue with this is that you now cant use 0 in your array, or it will terminate early.

A better way would be to pre calculate the address at which to stop, given the array length. This address is one off the end of the array.

#include <cstdio>
using namespace std;

int main(int argc, char **argv) {
    puts("hi");
    int ia[] = {1,2,3,4,5};
    int* end = ia + 5;
    for (int *p = ia; p != end; ++p) {
        printf("Char is: %d\n", *p);
    }
    return 0;
}

Now we are getting towards the method used by standard library iterators. Now templates can deduce the size of the array.

i.e.

#include <iterator>
...

for (auto it = std::begin(ia); it != std::end(ia); ++it) {
    printf("Char is: %d\n", *it);
}

...

and finally, range based for also supports arrays.

for (auto i: ia)
{
    /* do something */
}
Sign up to request clarification or add additional context in comments.

1 Comment

Or even for range: for (int e : ia) { /*..*/ }.
2

Can anyone explain why this has happened?

You are accessing the array out of bounds. Your program has undefined behavior.

The line

int ia[5] = {1,2,3,4,5};

creates an array with exactly 5 elements. Accessing *p after you have accessed the last element of the array is not good.

You can use:

for (int *p = ia; p != std::end(ia); ++p) {

to make sure that you don't access the array out of bounds.

You will need to add:

#include <iterator>

to use std::end.

1 Comment

#include <iterator>
1

Alternatively use sizeof() operator to determine the number of elements:

for (int *p = ia; p < ia + sizeof(ia)/sizeof(*ia); ++p) {
    printf("Char is: %d\n", *p);
}

Comments

0

in fact the condition:

for( ; *p; )//...

will check whether the value in the address is equal to 0 or not so it stops only if the value is zero and of course this is not what you wanted; you wanted to increment the address until the last element but your code checks the value inside the address not the address itself morever the address after the lat element is not NULL.

to solve your problem you can count how many elements in the array and then inside the loop increment the pointer accordingly:

#include <cstdio>
using namespace std;

int main(int argc, char **argv) {
    puts("hi");
    int ia[5] = {1,2,3,4,5};
   int* end = &ia[0] + 4;
   for (int *p = ia; p <= end; ++p) {
        printf("Char is: %d\n", *p);
    }
   return 0;
}

Comments

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.