简体   繁体   中英

my for loop is making every value the last value (C++)

I have a user input a value, then define ports based on that value and the following 31 values. These ports should then be stored in an array, but for some reason when I call from the array every value is the last value. (For example, if a user enters 5000, every value in the array ends up being 5031). It's something wrong with storing the actual numbers in the array since if I print the values as they are being created they are all correct. Excuse the inelegant code, I'm a newbie. Thanks!

//enter own ports   
using namespace std;
    cout << "enter a port number between 1000-9999: "; // gets port from user input
    cin >> startingport;


for (int i=0; i<32; i++) // defines 32 ports starting with user input
    {
    sprintf(portchar, "%d", startingport+i);
    cout << "defining port: " << portchar << endl; // gives correct value
    portarray[i] = portchar;
    }

cout << portarray[0] << endl; // gives incorrect value

Sorry should have put this before-- I have definitions in another file. I need port to be a character, hence portchar

static int startingport;
static char portchar[6];
static char *portarray[32];

They will be pointing to the same underlying value, as you repeatedly use 'portchar' to print to and it happens to be a static char.

portarray[0] -> portarray[1] -> ... portarray[2] -> all pointing to 'portchar'

All of them are pointing to the shared char array. You need to fix a few things:

  1. Since portarray is declared as an array of pointers, you would need individual buffers to point to.

  2. Change portarray to be declared as an array of std::string. You would get a copy. Thus, you will have distinct values.

  3. Keep portarray as an array of pointers, but, allocate a new portchar for each iteration of the loop and store these pointers.

_3 is not great, as you would have to manage the memory yourself.

_2 is better, along with using a std::vector<> for portarray.

_1 is generating copies of strings, which you need to decide if you want to pay that cost.

First I want to echo Mike Seymour's comment that you should be using std::string s and a container, not char* and *char[] . The higher level abstractions help mitigate a lot of the common issues related to pointer management and arithmetic.

That said, this is a good teachable moment.

What went wrong

Let's begin by telling ourselves that a pointer ( * ) is nothing more than an address. Just like how I live at 555 First St, all objects in memory have an address. If I move out of my address and someone else moves in, when someone asks who lives at 555 First St, the answer at that moment will be whoever moved in, not me.

If pointers are just addresses, then what is an array of pointers? Well, it's just a list of addresses! Imagine a list with empty slots that can hold 32 addresses. This is what portarray is.

So what does your loop do? Well there are three basic operations:

sprintf(portchar, "%d", startingport+i);

This is equivalent to someone moving into the address portchar . The address is still the same, there's just something new in there now.

cout << "defining port: " << portchar << endl;

This is the same as asking who lives at that address. Of course, you know what this is, it's just startingport+1 since startingport+1 just moved in!

Finally:

portarray[i] = portchar;

Pay close attention to this. This says to copy down the address portchar into your list of addresses. Imagine you had a piece of paper and you wrote down "0: 555 First St" . This is not copying down who lives at that address, but the address itself. The next iteration of this loop, when it comes time to write down the address again, we'd write "1: 555 First St" , same as before.

So at the end of your loop, you'll have this nice list of addresses, and all of the addresses are exactly the same, because of course you never actually changed the address in your loop.

What can you do about it (without using std::string )

If you're willing to manually manage the memory pointed to by portarray , you can fix your issues using heap allocated memory. This is necessary because you need 32 unique addresses that you can put into portarray . Your statically allocated portchar gives you one address which is insufficiently.

// Assuming you've removed your portchar declaration
for (int i=0; i<32; i++) // defines 32 ports starting with user input
{
    portarray[i] = new char[6]; // This dynamically allocates memory
    sprintf(portarray[i], "%d", startingport+i);
    cout << "defining port: " << portarray[i] << endl; // gives correct value
}

cout << portarray[0] << endl; // gives correct value

To free up the memory later, you have to do:

for (int i=0; i<32; i++)
{
    delete[] portarray[i];
}

It looks messy, and that's because it is. As others have suggested, you can avoid this minefield by using std::string and containers. If your code is amenable to those abstractions, I highly recommend using them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM