简体   繁体   中英

For loop crashes program while trying to read array c++

Exercise: The vector A[1 to N] and a value s is given. Build the program that writes backwards every group of s elements. If s divided by N has a remainder, then the remaining values should be unchanged. If s is bigger than N (the nr of elements of the vector) than there will be no modification.

Lets say s = 4 and A = (1, 2, 3, 4, 5, 6, 7, 8)then after execution the values will be A = (4, 3, 2, 1, 8, 7, 6, 5)

My teacher requires this kind of vector: int n, A[n] where n is a value given by the user. And i think this is what is causing my program to crash when i read the final values. If not, where is the problem?

#include <iomanip>

using namespace std;

int ordering(int s, int n, int A[]);

int main()
{
    int n, A[n];
    int s;
    cout << "Vlera e s: ";
    cin >> s;

    if (s <= 0) 
    {
        return 1;
    }

    cout << "\nN: ";
    cin >> n;

    if (n <= 0) 
    {
        return 1;
    }

    cout << "\nVector:";
    for (int i = 0; i < n; i++)
    {
        A[i] = i + 1;
        cout << " " << A[i] << " ";
    }

    if (s > n)
    {
        cout << "\nNo change\n";
        return 0;
    }
    else
    {
        ordering(s, n, A);
    }

    cout << "\nNew vector:";
    for (int i = 0; i < n; i++)
    {
        cout << " " << A[i] << " ";
    }

    return 0;
}

int ordering(int s, int n, int A[])
{
    int counter = 0;
    for (int i = 0, divider = n / s; i < divider; i++)
    {
        int decrease = 0;
        for (int j = counter, a = counter + s; j < a; j++)
        {
            A[j] = a - decrease;
            decrease++;
        }
        counter += s;
    }
    return 0;
}

This program using a compiler extension to allow variable sized arrays in the form myArray[variableSize] . Whilst not standard, it does work on some compilers.

You are using this feature here:

int n, A[n];

However, n is uninitialised at this point. This is undefined behaviour even on the compilers that support such variable sized arrays. One possible (but not the only) outcome of undefined behaviour is your program crashing.

Undefined behaviour can do anything in theory, but the realistic set of things in can do in reality is smaller. Some of the likely implications of the undefined behaviour here:

  1. n has some huge number in it, from whatever last used that bit of memory. As a result, A is huge.
  2. n is 0. You can't have a 0 sized array. If the compiler doesn't notice this, you could end up trashing memory.
  3. Since n is uninitialised, the optimiser for the compiler (they usually do very some optimisations, even when on -O0) assumes that undefined behaviour cannot occur, which is violated here, leading to strange behaviour.
  4. n is a reasonable value, just by luck, but because it is later updated it no longer matches the size of the array and you end up reading / writing memory off the end of the array, trashing memory.

There are other possibilities, but this gives an idea of the kind of things that can happen as a result of this specific instance of undefined behaviour. If you're interested to know more, using a debugger to step through the code in assembly (you only need learn a little to understand the output, it looks more scary than it need be) will show you what's actually happening.

Variable length arrays is not a standard C++ feature.

int n, A[n];

Moreover in the above declaration the variable n was not initialized. So in any case the program has undefined behavior.

Instead of an array you could use the standard class template std::vector .

The program can look simpler and more safer is to use standard algorithms such as, for example, std::reverse .

Here is a demonstrative program.

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <numeric>

void reorder( std::vector<int> &v, size_t s )
{
    if ( not ( s < 2 ) )
    {
        for ( auto last = std::end( v ); 
              not (std::distance( std::begin( v ), last ) < s );  )
        {
            auto first = std::prev( last, s );
            std::reverse( first, last );
            last = first;
        }
    }       
}

int main() 
{
    std::cout << "Vlera e s: ";

    size_t s = 0;
    std::cin >> s;

    std::cout << "N: ";

    size_t n = 0;
    std::cin >> n;

    std::vector<int> v( n );

    std::iota( std::begin( v ), std::end( v ), 1 );

    putchar( '\n' );

    for ( const auto &item : v )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';

    reorder( v, s );

    for ( const auto &item : v )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';

    return 0;
}

The program output might look like

Vlera e s: 4
N: 10

1 2 3 4 5 6 7 8 9 10 
1 2 6 5 4 3 10 9 8 7

But it seems you need write the corresponding code yourself using loops. In this case the program can look like

#include <iostream>
#include <vector>

void reorder( std::vector<int> &v, size_t s )
{
    if ( not ( s < 2 ) )
    {
        for ( auto n = v.size(); !( n < s ); n -= s )
        {
            for ( size_t i = 0; i < s / 2; i++ )
            {
                int value = v[n - s + i];
                v[n - s + i] = v[n - i - 1];
                v[n - i - 1] = value;
            }
        }
    }       
}

int main() 
{
    std::cout << "Vlera e s: ";

    size_t s = 0;
    std::cin >> s;

    std::cout << "N: ";

    size_t n = 0;
    std::cin >> n;

    std::vector<int> v( n );

    int value = 1;

    for ( auto &item : v ) item = value++; 

    putchar( '\n' );

    for ( const auto &item : v )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';

    reorder( v, s );

    for ( const auto &item : v )
    {
        std::cout << item << ' ';
    }
    std::cout << '\n';

    return 0;
}

The program output might look as already shown above

Vlera e s: 4
N: 10

1 2 3 4 5 6 7 8 9 10 
1 2 6 5 4 3 10 9 8 7

Passing variable as array size is not valid you need to use constant const int n or create dinamic array int* arr = new int[n]; , that array will be created in runtime, and you can pass variable as it size. Dont forget to delete that array whet it goes out of scope delete[] arr;

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