Insert elements into array of C++ lists

Asked

Viewed 1,731 times

3

I’m having trouble inserting elements into a list array. The program prints the quantity_de_vertices variable and then a runtime error occurs.

#include <iostream>
#include <list>
#include <vector>
#include <stdio.h>
using namespace std;

int main(int argc, char *argv[]){
    FILE *arq = fopen(argv[1], "r") ;
    int quantidade_de_vertices, vertice1, vertice2, cont;
    
    fscanf(arq, "%*c %*s %d %*d", &quantidade_de_vertices);
    cout << quantidade_de_vertices;

    vector< list<int> > adj(quantidade_de_vertices);

    while(!feof(arq)){
        fscanf(arq, "%*c %d %d", &vertice1, &vertice2);
        adj[vertice1].push_back(vertice2); //essa é a linha com o erro
    }
    fclose(arq);
    return 0;
}

Apparently the problem is in the operator [] of the vector function that does not accept the variable vertice1, because when I tested changing the line:

adj[vertice1]. push_back(vertice2);

for

adj[1]. push_back(vertice2);

and the program ran normally. The files are formatted as follows:

p edge 4 6

and 1 2

and 1 3

and 1 4

and 2 3

and 2 4

and 3 4

EOF

2 answers

2

The problem is in fscanf and in the reading of the line terminus, the \n.

In the first line works well, and reads the 4 values but in the second line, through debug quickly you see that the reading did not work well:

inserir a descrição da imagem aqui

In which the vertice2 got 4201420 and the vertice1 with 2686760.

This is because the \n of the first line was not consumed and spoiled the successive readings. Soon the solution is simple, just change the first fscanf for:

fscanf(arq, "%*c %*s %d %*d\n", &quantidade_de_vertices); //agora com \n no fim

And what’s inside the while also:

fscanf(arq, "%*c %d %d\n", &vertice1, &vertice2); //também com \n

2

Firstly, it is not advisable to mix operations of e/s C++ (Cin/Cout) and C (printf/scanf), you need to treat errors of two things (C++ and C) instead of one (C++ or C).

Second, when scanf/fscanf/sscanf is used in production systems (and not only in test and exercise programs) it is necessary to ALWAYS check the scanf result, to treat errors that may have occurred.

Below I modified the original program to show the fscanf result.

#include <iostream>
#include <list>
#include <vector>
#include <stdio.h>
using namespace std;

int main(int argc, char *argv[])
{
  int quantidade_de_vertices, vertice1, vertice2, cont;

  FILE* arq = fopen(argv[1], "r");

  int n_cpos_lidos;

  n_cpos_lidos = fscanf(arq, "%*c %*s %d %*d", &quantidade_de_vertices);
  cout << "* cpos lidos: " << n_cpos_lidos << " / n_vertices: " << quantidade_de_vertices << '\n';

  vector< list<int> > adj(quantidade_de_vertices);

  while (!feof(arq))
  {
    n_cpos_lidos = fscanf(arq, "%*c %d %d", &vertice1, &vertice2);
    cout << "* inserindo: cpos lidos: " << n_cpos_lidos << " / v1: " << vertice1 << " / v2: " << vertice2 << '\n';
    adj[vertice1].push_back(vertice2); //essa é a linha com o erro
  }

  cout << "* eof\n";

  fclose(arq);
  return 0;
}

Running this program with the data shown in the question (including with the EOF that does not know if it is really in the file, or if it is just an end of file indication in the question).

The result is this:

~/Projects/testes/so]
$./223533 dados_223533.txt 
* cpos lidos: 1 / n_vertices: 4
* inserindo: cpos lidos: 0 / v1: 0 / v2: 32662
* inserindo: cpos lidos: 2 / v1: 1 / v2: 2
* inserindo: cpos lidos: 0 / v1: 1 / v2: 2
* inserindo: cpos lidos: 2 / v1: 1 / v2: 3
* inserindo: cpos lidos: 0 / v1: 1 / v2: 3
* inserindo: cpos lidos: 2 / v1: 1 / v2: 4
* inserindo: cpos lidos: 0 / v1: 1 / v2: 4
* inserindo: cpos lidos: 2 / v1: 2 / v2: 3
* inserindo: cpos lidos: 0 / v1: 2 / v2: 3
* inserindo: cpos lidos: 2 / v1: 2 / v2: 4
* inserindo: cpos lidos: 0 / v1: 2 / v2: 4
* inserindo: cpos lidos: 2 / v1: 3 / v2: 4
* inserindo: cpos lidos: 0 / v1: 3 / v2: 4
* inserindo: cpos lidos: 0 / v1: 3 / v2: 4
* inserindo: cpos lidos: 0 / v1: 3 / v2: 4
* inserindo: cpos lidos: -1 / v1: 3 / v2: 4
* eof

[~/Projects/testes/so]
$

It is noticed that there have been many failures in reading, the program and the file are out of sync. As explained in the other answer, this is caused by the end-of-line characters.

A simple way to mitigate the end-of-line problem in this program is to put a space before reading the first character. Change fscanf(arq, "%*c %*... for fscanf(arq, " %*c %*.... That space before "%c" consumes end-of-line characters that may exist.

The program is now like this:

#include <iostream>
#include <list>
#include <vector>
#include <stdio.h>
using namespace std;

int main(int argc, char *argv[])
{
  int quantidade_de_vertices, vertice1, vertice2, cont;

  FILE* arq = fopen(argv[1], "r");

  int n_cpos_lidos;

  n_cpos_lidos = fscanf(arq, " %*c %*s %d %*d", &quantidade_de_vertices);
  cout << "* cpos lidos: " << n_cpos_lidos << " / n_vertices: " << quantidade_de_vertices << '\n';

  vector< list<int> > adj(quantidade_de_vertices);

  while (!feof(arq))
  {
    n_cpos_lidos = fscanf(arq, " %*c %d %d", &vertice1, &vertice2);
    cout << "* inserindo: cpos lidos: " << n_cpos_lidos << " / v1: " << vertice1 << " / v2: " << vertice2 << '\n';
    adj[vertice1].push_back(vertice2); //essa é a linha com o erro
  }

  cout << "* eof\n";

  fclose(arq);
  return 0;
}

The result now is this:

[~/Projects/testes/so]
$./223533 dados_223533.txt 
* cpos lidos: 1 / n_vertices: 4
* inserindo: cpos lidos: 2 / v1: 1 / v2: 2
* inserindo: cpos lidos: 2 / v1: 1 / v2: 3
* inserindo: cpos lidos: 2 / v1: 1 / v2: 4
* inserindo: cpos lidos: 2 / v1: 2 / v2: 3
* inserindo: cpos lidos: 2 / v1: 2 / v2: 4
* inserindo: cpos lidos: 2 / v1: 3 / v2: 4
* inserindo: cpos lidos: 0 / v1: 3 / v2: 4
* inserindo: cpos lidos: 0 / v1: 3 / v2: 4
* inserindo: cpos lidos: -1 / v1: 3 / v2: 4
* eof

[~/Projects/testes/so]
$

Almost certain! There is that problem at the end, with n_cpos_lidos equal to 0 and a -1, which the program is not dealing with. The first problem n_cpos_read equal to 0 is surely caused by that EOF at the end of the file. Taking the EOF from the file the result is like this:

[~/Projects/testes/so]
$./223533 dados_223533.txt 
* cpos lidos: 1 / n_vertices: 4
* inserindo: cpos lidos: 2 / v1: 1 / v2: 2
* inserindo: cpos lidos: 2 / v1: 1 / v2: 3
* inserindo: cpos lidos: 2 / v1: 1 / v2: 4
* inserindo: cpos lidos: 2 / v1: 2 / v2: 3
* inserindo: cpos lidos: 2 / v1: 2 / v2: 4
* inserindo: cpos lidos: 2 / v1: 3 / v2: 4
* inserindo: cpos lidos: -1 / v1: 3 / v2: 4
* eof

[~/Projects/testes/so]
$

It got better, but it still has that "cpos read: -1" that the program is not treating right. The cause of this error is that the program is treating the end of file in the wrong way: the end of file treatment should be done immediately after fscanf, and not back at the beginning of the loop. The modification to do the treatment the right way is like this:

#include <iostream>
#include <list>
#include <vector>
#include <stdio.h>
using namespace std;

int main(int argc, char *argv[])
{
  int quantidade_de_vertices, vertice1, vertice2, cont;

  FILE* arq = fopen(argv[1], "r");

  int n_cpos_lidos;

  n_cpos_lidos = fscanf(arq, " %*c %*s %d %*d", &quantidade_de_vertices);
  cout << "* cpos lidos: " << n_cpos_lidos << " / n_vertices: " << quantidade_de_vertices << '\n';

  vector< list<int> > adj(quantidade_de_vertices);

  for (;;)
  {
    n_cpos_lidos = fscanf(arq, " %*c %d %d", &vertice1, &vertice2);
    if ( n_cpos_lidos != 2)
    {
      if (feof(arq))
        cout << "* fim de arquivo\n";
      else
        cout << "* erro de formato na leitura\n";
     break;
    }
    cout << "* inserindo: cpos lidos: " << n_cpos_lidos << " / v1: " << vertice1 << " / v2: " << vertice2 << '\n';
    adj[vertice1].push_back(vertice2); //essa é a linha com o erro
  }

  fclose(arq);
  return 0;
}

The way out now is like this:

[~/Projects/testes/so]
$./223533 dados_223533.txt 
* cpos lidos: 1 / n_vertices: 4
* inserindo: cpos lidos: 2 / v1: 1 / v2: 2
* inserindo: cpos lidos: 2 / v1: 1 / v2: 3
* inserindo: cpos lidos: 2 / v1: 1 / v2: 4
* inserindo: cpos lidos: 2 / v1: 2 / v2: 3
* inserindo: cpos lidos: 2 / v1: 2 / v2: 4
* inserindo: cpos lidos: 2 / v1: 3 / v2: 4
* fim de arquivo

[~/Projects/testes/so]
$

The operation is now correct, with the data provided in the question.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.