Игнорирование условия в While С++

284
19 октября 2017, 10:57

Задание такое: заполнить матрицу Nного порядка и посчитать

1) Сумму элементов в тех строках, которые не содержат отрицательных элементов

2) минимум среди сумм элементов диагонале, параллельных главной диагонали матрицы. Если первое работает на ура, то со вторым возникли такие затруднения:

При подсчёте сумм диагоналей параллельных главной, в цикле где это происходит есть вылет за массив у переменных x и y хотя в while чётко прописано, что если ((x < N - 1) ИЛИ (y < N - 1)) то считать сумму диагонали, однако это условие игнорируется и x выходит дальше за массив. Наблюдается в g++ и visual-c Вопрос, почему игнорируются условия в while?

// PR5_din_arrays.cpp: определяет точку входа для консольного приложения.
//
/*Дана целочисленная квадратная матрица. Определить:
1) Сумму элементов в тех строках, которые не содержат отрицательных элементов
2) минимум среди сумм элементов диагонале, параллельных главной диагонали матрицы.
*/
// PR5_din_arrays.cpp: определяет точку входа для консольного приложения.
//
/*Дана целочисленная квадратная матрица. Определить:
1) Сумму элементов в тех строках, которые не содержат отрицательных элементов
2) минимум среди сумм элементов диагонале, параллельных главной диагонали матрицы.
*/
#include "stdafx.h"
#include <time.h>
#include <iomanip>
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    int N = 2;
    cout << "input the size of matrix" << endl;
    cin >> N;
    while (N < 2)
    {
        cout << "incorrect value!" << endl;
        cout << "input the size of matrix" << endl;
        cin >> N;
    }
    /* в куске выше я объявляю N которая отвечает за порядок матрицы. После её ввода идёт защита от дурака, которая не пускает дальше, если введённое значение меньше 2.
    В случае если будет матрица первого порядка, то задача потеряет смысл*/
    int **matrix = new int*[N];
    for (int count = 0; count < N; count++)
    {
        matrix[count] = new int[N];
    }
    /*выше объявляю саму матрицу*/
    int *sum = new int[N]; // в этот массив пишутся суммы строк. Должен быть динамическим ибо мы не знаем какого порядка будет матрица
    int ds = (N - 1) * 2; // это формула вычисления количества диагоналей параллельных главной. Чтобы включить сюда главную диагональ, нужно к полученному результату прибавить единицу
    int *diasum = new int[ds+1]; // массив в который будут попадать суммы диагоналей
    srand(time(NULL));
    cout << "Original array:" << endl;
    for (int i = 0; i < N; i++)
    {
        sum[i] = 0; // обнуление массива сумм! ОБЯЗАТЕЛЬНО! иначе на выходе получим очень интересные и многозначные данные которые называются мусором
        for (int j = 0; j < N; j++)
        {
            matrix[i][j] = rand() % 101 - 50;
            cout << setw(6) << left << matrix[i][j]; // тут setw(6) устанавливает расстояние между символами потока вывода, left сдвигает всё влево. ЧТОБЫ РАБОТАЛО НУЖЕН <iomanip>
        }
        cout << endl;
    }
    cout << "sdelan vyvod - perehod k vychisleniyu summy stroki" << endl;
    /*в куске выше я рандомил матрицу от -50 до 50(100 чисел и сдвиг по числовой линии влево на 50 101 потому что 0 тоже число*/
    //вычисления
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            if (matrix[i][j] < 0)
            {
                sum[i] = 0;
                break;
            }
            else
            {
                sum[i] = sum[i] + matrix[i][j];
            }
        }
    }cout << "vycheslena stroka - perehod k onuleniyu DIASUM" << endl;/*выше я иду по строке и проверяю число на отрицательность. Если отрицательное - обнуляю сумму и выхожу из цикла, таким образом перехожу на след. строку
     Если же всё окей, то просто прибавляю число в sum[i]. */
    /*
    _____________________________________________________________________
    Ниже пойдёт отработка диагоналей
    _____________________________________________________________________
    */
    for (int i = 0; i < ds; i++)
    {
        diasum[i] = 0;
        cout << diasum[i] << "  ";
    }
    cout << endl;
    cout << "DIASUM obnulena - perehod k vychisleniyu summy diagonali - 1 prohod" << endl;
    int x = 0;
    int y = 0;
    int iter = 0; // Сюда ловим место на котором мы остановилис в цикле ниже, чтобы с него затем продолжить. 
    for (int i = 1; i < N; i++)
    {
        x = i;
        y = 0;
        cout << x << "   " << y << "   " << matrix[y][x] << endl;
        while ((x < N - 1) || (y < N - 1))
        {
            diasum[i - 1] = diasum[i - 1] + matrix[y][x]; // p.s вот здесь и происходят интересные вещи. при N = 4 x не должен быть больше 3, но он таки почему-то больше, хотя в цикле while написано о том, что если x или y больше 3 то вывалиться и посчитать следующую диагональ(или идти дальше если цикл for закончился
            x++;
            y++;
            iter = i - 1;
        }
    }
    for (int i = 0; i <= iter; i++) //вывод сумм чисел, пока что в лобешник все подряд.
    {
        cout << "      " << diasum[i];
    }
    cout << endl;
    cout << "DIASUM obnulena - perehod k vychisleniyu summy diagonali - 2 prohod" << endl;
    for (int i = 1; i < N; i++)
    {
        y = i;
        x = 0;
        cout << x << "   " << y << "   " << matrix[y][x] << endl;
        while ((y < N - 1) || (x < N - 1))
        {
            diasum[iter + i] = diasum[iter + i] + matrix[y][x]; // а здесь после нескольких шагов можно поймать ACCESS_VIOLATION
            x++;
            y++;
        }
    }
// конец блока отработки диагоналей.
    for (int i = 0; i < ds; i++) //вывод сумм чисел, пока что в лобешник все подряд.
    {
        cout << "      " << diasum[i];
    }
    cout << endl;
    cout << "perehod k vyvodu" << endl;
    for (int i = 0; i < N; i++) //вывод сумм чисел, пока что в лобешник все подряд.
    {
        cout <<"      " <<sum[i];
    }
        cout << endl;
        //cout << ds;
        system("pause"); // задерживаем консоль до ввода клавиши
    return 0;
}

Примечания 1. я знаю о том, что в коде может быть немного странная работа с дин.массивом diasum 2. код комментировался до написания куска отработки диагоналей и был прокомментирован для одногруппников.

Answer 1

Должно быть while ((x < N - 1) && (y < N - 1)). Так как Вы проверяете И тот (x) И тот (y) диапазон, а не хотя бы один.

Answer 2

Рассмотрим Ваш цикл while:

x = i;
y = 0;
while ((x < N - 1) || (y < N - 1)) {
    //...
    x++;
    y++;
}

Перед циклом x у нас всегда больше нуля. y же всегда будет равно нулю. Условие цикла гласит продолжать пока x меньше N - 1 ИЛИ y меньше N - 1

На каждой итерации x и y увеличиваются на 1. Всё это значит, что при i == 2 мы уже получим выход за пределы массива. Предлагаю для простоты рассмотреть примерчик. Пусть N == 3, i == 1.Тогда x == 1, y == 0.Получаем условие: (1 < 2) || (0 < 2) оно дает true, поэтому продолжаем цикл.В цикле x и y увеличиваются.Дальше по итерациям: (2 < 2) || (1 < 2) == true (3 < 2) || (2 < 2) == false Вышли из while и начинается новая итерация for: x == 2, y == 0 (2 < 2) || (0 < 2) == true (3 < 2) || (1 < 2) == true Как видим, x уже равен трем, а условие дает true, поэтому мы успешно заходим в цикл и выходим за пределы выделенной памяти.

READ ALSO
Разница между функциями wsprintfW() и swprintf_s()

Разница между функциями wsprintfW() и swprintf_s()

Собственно не могу понять в чем же разница между 2мя этими функциями, когда они дают идентичные результаты

330
Вызов функции из подгружаемого HTML

Вызов функции из подгружаемого HTML

Доброго времени сутокСобственно возникла одна проблема

307