Сбой при назначении вектора

#c #c 11 #visual-c #c 14

Вопрос:

 vector< vector<int> > resizeVector(vector< vector<int> > m)
{
    vector< vector<int> > newMatrix;
    int i,j;

    for (i = 0; i < m[i].size(); i  )
    {
        for(j = 0; j < m[j].size(); j  )
        {
            newMatrix[i][j] = m[i][j];
        }
    }
    return (newMatrix);
}
 

Я создаю программу, которая будет выполнять множество манипуляций с матрицей, и этот раздел выходит из строя, и я точно не знаю почему. Я сузил круг поисков до следующей строки:

 newMatrix[i][j] = m[i][j];
 

Он выходит из строя прямо здесь, и я не знаю, почему.

Ответ №1:

В дополнение к тому, что опубликовал @Saurav, newMatrix пусто, поэтому вы не можете присваивать значения newMatrix[i][j] . Вы можете исправить это, инициализировав векторы заданного размера:

 vector< vector<int> > resizeVector(vector< vector<int> > m)
{
    vector< vector<int> > newMatrix(m.size());
    int i,j;

    for (i = 0; i < m.size(); i  )
    {
        newMatrix[i].resize(m[i].size());
        for(j = 0; j < m[i].size(); j  )
        {
            newMatrix[i][j] = m[i][j];
        }
    }
    return (newMatrix);
}
 

Перед циклами for мы инициализируем newMatrix , чтобы m.size() внутри него было много пустых векторов (векторы пусты из-за их конструктора по умолчанию). Во время каждой итерации внешнего цикла for мы гарантируем, что каждый вектор внутри newMatrix имеет правильный размер, используя resize функцию-член.

Обратите внимание, что если вам нужна копия вектора, вы можете просто написать:

 vector< vector<int> > newMatrix(m);
 

Ответ №2:

Ваши чеки неверны. Вместо этого это должно быть

 for (i = 0; i < m.size(); i  )        // m.size() gives the number of rows 
{
    for(j = 0; j < m[i].size(); j  )  // m[i].size() gives the number of columns in the row
 

Ответ №3:

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

Поскольку вы не переходите в новый размер, трудно точно знать, чего вы пытаетесь достичь. Вот почему у меня нет более четких советов о том, как это исправить.

Ответ №4:

Если вы хотите выделить вектор вектора, вам нужно выделить память для матрицы, прежде чем индексировать ее. Поэтому вам придется использовать что-то вроде

 newMatrix.resize(size);
for (int i = 0; i < size;   i) {
    newMatrix[i].resize(size);
}
 

Или вы можете использовать векторный метод .push_back() для добавления значений в вектор без предварительного выделения памяти.

Ответ №5:

vector s operator[] возвращает ссылку на указанный элемент без проверки границ.

Это означает, что он не изменяет размер вектора волшебным образом или не выполняет никаких других операций для обеспечения существования элемента. Если элемент не существует, результатом является неопределенное поведение, что означает, что может произойти все, что угодно. На практике это часто приводит к тому, что программа обращается к недопустимой области памяти, что приводит к сбою.

Вышесказанное справедливо даже для простого vector<int> . Вы усугубили свои проблемы, работая с a vector<vector<int> > (каждый элемент a vector<vector<int> > -это a vector<int> ).

Ваша функция на самом деле немного захватывает дух тем, сколько раз она потенциально вызывает неопределенное поведение. Вы случайно получаете сбой в заявлении newMatrix[i][j] = m[i][j] , но вероятность неопределенного поведения на самом деле возникает до этого.

Во внешнем цикле m[i] не будет существовать, если m.size() (что ваш код не проверяет) имеет нулевое значение. Если m.size() равно нулю, это приводит к тому, что оценка m[i] (as m.operator[](i) ) имеет неопределенное поведение.

По сути, вам необходимо убедиться , что любой индекс i действителен перед оценкой m[i] , а затем ТАКЖЕ убедиться, что j это действительный индекс m[i] перед оценкой m[i][j] . А затем сделайте то же самое для newMatrix . Ваш код вообще ничего этого не делает. Более правильный рендеринг вашей функции (при условии, что целью является создание копии m ) — это

 vector< vector<int> > resizeVector(vector< vector<int> > m)
{
    vector< vector<int> > newMatrix;
    int i,j;

    newMatrix.resize(m.size());    //  necessary to ensure we can access newMatrix[i] in the loop below

    for (i = 0; i < m.size(); i  )     //   ensure i is a valid index of m
    {
        // newMatrix[i].size() is still zero, so we need to resize for use in the inner loop

        newMatrix[i].resize(m[i].size()); 

        for(j = 0; j < m[i].size(); j  )   // ensure j is a valid index of m[i]
        {
            newMatrix[i][j] = m[i][j];
        }
    }
    return (newMatrix);
}
 

Теперь дело в том, что ваш код фактически воссоздает функциональность, которую уже предоставляет vector. Таким образом, мы могли бы довольно просто заменить тело функции на

 vector< vector<int> > resizeVector(vector< vector<int> > m)
{
      vector< vector<int> > newMatrix(m);  
      return newMatrix;
}
 

или даже с

 vector< vector<int> > resizeVector(vector< vector<int> > m)
{
      return m;
}
 

Это означает, что ваша функция (в том виде, в каком я ее изменил) названа неправильно — она ничего не изменяет. На самом деле, это довольно бессмысленно, так как, если вызывающий абонент делает это

 x = resizeVector(y);
 

он может достичь того же эффекта вообще без вашей функции, просто как

 x = y;
 

что также более эффективно (нет вызова функции, нет создания копий для передачи по значению и т. Д.).