Функция синтаксического анализа анализирует файл, но только частично - PullRequest
0 голосов
/ 07 августа 2020

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

5
3
1 3
1 4
1 5
3
2 3
2 4
2 5
2
3 1
3 2
3
4 1
4 2
4 5
3
5 1
5 2
5 4

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

graph_vertex_t* read_vertex(FILE *fp, graph_vertex_t *last_vertex) 
{
    graph_vertex_t *current_vertex;
    
    graph_edge_t *tmp_edge;
    
    graph_edge_t *last_edge;
    
    char *token;
    
    boolean_t error = false;
    
    current_vertex = (graph_vertex_t *)malloc(sizeof(graph_vertex_t));
    
    int tmp_number_edges = 1;
    /*Temporary character string used to read line in file. */
    char *tmp;
    /*Allocating memory for string. Again I'm assuming 64 charcters is*/
    /*all I need. */
    tmp = malloc(sizeof(char) * 64);
    while (fgets(tmp, 
                 63, 
                 fp) != NULL 
                 &&
                 tmp_number_edges > 0)
    {   
        tmp[strcspn(tmp, "\n")] = 0;
        /* Check if the line contains a vertex number. */
        if (is_number(tmp))
        {
            /* Set the line to the vertex number. */
            tmp_number_edges = atoi(tmp);
        }
        else
        {           
            /* check if line has the right format. */
            token = strtok(tmp, " \t");
            if (is_number(token))
            {
                /* Set the identifier of the vertex. */
                current_vertex->identifier = atoi(token);
                current_vertex->next_vertex_p = last_vertex;
            }
            else
            {
                error = true;
            }
            
            token = strtok(NULL, " \t");
            if (is_number(token))
            {
                /* Make new edge. */
                tmp_edge = (graph_edge_t *)malloc(sizeof(graph_edge_t));
                tmp_edge->adjac_vertex_p = (graph_vertex_t *)malloc(sizeof(graph_vertex_t));
                tmp_edge->adjac_vertex_p->identifier = atoi(token);
                tmp_edge->next_edge_p = last_edge;              
                last_edge = tmp_edge;
                printf(" %d", tmp_edge->adjac_vertex_p->identifier);
            }
            else
            {
                error = true;
            }
            tmp_number_edges--;
        }
    }
    current_vertex->edge_list_p = tmp_edge;
    if(error)
    {
        current_vertex = NULL;
    }
    return(current_vertex);
}

Эта функция вызывается в for l oop, который выполняет цикл для количества вершин. Затем печатается некоторая информация:

printf("connecting to: ");
            
current_vertex = read_vertex(fp,
                             last_vertex);
printf(" found vertex ID: %d \n", current_vertex->identifier);

Поэтому я ожидаю, что результат будет выглядеть примерно так:

подключение к: 3 4 5 ID найденной вершины: 1
подключение to: 3 4 5 ID найденной вершины: 2
соединение с: 1 2 ID найденной вершины: 3
соединение с: 1 2 5 ID найденной вершины: 4
соединение с: 1 2 4 ID найденной вершины: 5

Но на самом деле это выглядит так:

подключение к: 3 4 5 ID найденной вершины: 1
подключение к: 3 ID найденной вершины : 2
соединение с: 5 ID найденной вершины: 2
соединение с: 1 ID найденной вершины: 3
соединение с: 1 2 5 ID найденной вершины: 4
соединение с: 1 ID найденной вершины : 5

Мы видим, что для ID 1 и 4 вывод правильный, но для остальных - нет. Что вызывает такое поведение? как я могу это исправить?

EDIT:

Вот определения graph_vertex_t и graph_edge_t.

* Structure used to hold a graph vertex information. */
typedef struct graph_vertex
{
    int identifier;
    struct graph_vertex *next_vertex_p;
    struct graph_edge *edge_list_p;
    boolean_t visited;
} graph_vertex_t;

/* Structure used to hold a graph edge information. */
typedef struct graph_edge
{
    struct graph_vertex *adjac_vertex_p;
    struct graph_edge *next_edge_p;
} graph_edge_t;

1 Ответ

1 голос
/ 07 августа 2020

Из вашего замечания

Сначала мне нужно понять sscanf

, чтобы помочь вам прочитать, вот несколько предложений, из-за любого запоминания в ваших структурах

Первое предложение без проверки номеров на разделенных строках:

#include <stdio.h>

int main()
{
  int nVertices, verticesRank;
  
  if ((scanf("%d", &nVertices) != 1) ||
      (nVertices < 0)) {
    fputs("wrong number of vertices\n", stderr);
    return -1;
  }

  for (verticesRank = 0; verticesRank < nVertices; verticesRank += 1) {
    int nGroups, groupRank, vertex;
    
    if ((scanf("%d", &nGroups) != 1) ||
        (nGroups < 0)) {
      fprintf(stderr, "wrong number of groups in vertices #%d\n", verticesRank);
      return -1;
    }
    
    for (groupRank = 0; groupRank < nGroups; groupRank += 1) {
      int a, b;
      
      if ((scanf("%d%d", &a, &b) != 2) ||
          (a < 1) || (b < 1)) {
        fprintf(stderr, "wrong vertex IDs group #%d vertices #%d\n",
               groupRank, verticesRank);
        return -1;
      }
      
      if (groupRank == 0) {
        vertex = a;
        printf("vertex %d connecting", a);
      }
      else if (a != vertex) {
        fprintf(stderr, "wrong vertex ID group #%d vertices #%d, %d rather than %d\n",
                groupRank, verticesRank, a, vertex);
        return -1;
      }
      printf(" %d", b);
    }
    putchar('\n');
  }
  
  return 0;
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -Wall c.c
pi@raspberrypi:/tmp $ cat > v
5
3
1 3
1 4
1 5
3
2 3
2 4
2 5
2
3 1
3 2
3
4 1
4 2
4 5
3
5 1
5 2
5 4
pi@raspberrypi:/tmp $ ./a.out <v
vertex 1 connecting 3 4 5
vertex 2 connecting 3 4 5
vertex 3 connecting 1 2
vertex 4 connecting 1 2 5
vertex 5 connecting 1 2 4
pi@raspberrypi:/tmp $ 

Вторая версия проверяет наличие правильного количества значений на строку:

#include <stdio.h>

int main()
{
  char line[64];
  int nVertices, verticesRank;
  int dummy;
  
  if ((fgets(line, sizeof(line), stdin) == NULL) ||
      (sscanf(line, "%d%d", &nVertices, &dummy) != 1) ||
      (nVertices < 0)) {
    fputs("wrong number of vertices\n", stderr);
    return -1;
  }

  for (verticesRank = 0; verticesRank < nVertices; verticesRank += 1) {
    int nGroups, groupRank, vertex;
    
    if ((fgets(line, sizeof(line), stdin) == NULL) ||
        (sscanf(line, "%d%d", &nGroups, &dummy) != 1) ||
        (nGroups < 0)) {
      fprintf(stderr, "wrong number of groups in vertices #%d\n", verticesRank);
      return -1;
    }
    
    for (groupRank = 0; groupRank < nGroups; groupRank += 1) {
      int a, b;
      
      if ((fgets(line, sizeof(line), stdin) == NULL) ||
          (sscanf(line, "%d%d%d", &a, &b, &dummy) != 2) ||
          (a < 1) || (b < 1)) {
        fprintf(stderr, "wrong vertex IDs group #%d vertices #%d\n",
               groupRank, verticesRank);
        return -1;
      }
      
      if (groupRank == 0) {
        vertex = a;
        printf("vertex %d connecting", a);
      }
      else if (a != vertex) {
        fprintf(stderr, "wrong vertex ID group #%d vertices #%d, %d rather than %d\n",
                groupRank, verticesRank, a, vertex);
        return -1;
      }
      printf(" %d", b);
    }
    putchar('\n');
  }
  
  return 0;
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -Wall cc.c
pi@raspberrypi:/tmp $ ./a.out <v
vertex 1 connecting 3 4 5
vertex 2 connecting 3 4 5
vertex 3 connecting 1 2
vertex 4 connecting 1 2 5
vertex 5 connecting 1 2 4
pi@raspberrypi:/tmp $ 

примечание Я не проверяю, есть ли что-то еще, кроме числа, поэтому первая строка считается правильной, это 5aze например, если вам нужно проверить:

#include <stdio.h>

int main()
{
  char line[64];
  int nVertices, verticesRank;
  char dummy;
  
  if ((fgets(line, sizeof(line), stdin) == NULL) ||
      (sscanf(line, "%d%c", &nVertices, &dummy) != 2) ||
      (nVertices < 0) ||
      (dummy != '\n')) {
    fputs("wrong number of vertices\n", stderr);
    return -1;
  }

  for (verticesRank = 0; verticesRank < nVertices; verticesRank += 1) {
    int nGroups, groupRank, vertex;
    
    if ((fgets(line, sizeof(line), stdin) == NULL) ||
        (sscanf(line, "%d%c", &nGroups, &dummy) != 2) ||
        (nGroups < 0) ||
        (dummy != '\n')) {
      fprintf(stderr, "wrong number of groups in vertices #%d\n", verticesRank);
      return -1;
    }
    
    for (groupRank = 0; groupRank < nGroups; groupRank += 1) {
      int a, b;
      
      if ((fgets(line, sizeof(line), stdin) == NULL) ||
          (sscanf(line, "%d%d%c", &a, &b, &dummy) != 3) ||
          (a < 1) || (b < 1) ||
          (dummy != '\n')) {
        fprintf(stderr, "wrong vertex IDs group #%d vertices #%d\n",
               groupRank, verticesRank);
        return -1;
      }
      
      if (groupRank == 0) {
        vertex = a;
        printf("vertex %d connecting", a);
      }
      else if (a != vertex) {
        fprintf(stderr, "wrong vertex ID group #%d vertices #%d, %d rather than %d\n",
                groupRank, verticesRank, a, vertex);
        return -1;
      }
      printf(" %d", b);
    }
    putchar('\n');
  }
  
  return 0;
}

Компиляция и выполнение:

pi@raspberrypi:/tmp $ gcc -Wall cc.c
pi@raspberrypi:/tmp $ ./a.out <v
vertex 1 connecting 3 4 5
vertex 2 connecting 3 4 5
vertex 3 connecting 1 2
vertex 4 connecting 1 2 5
vertex 5 connecting 1 2 4
pi@raspberrypi:/tmp $ 

Обратите внимание, что даже дополнительный пробел (вне новой строки) после последнего ожидаемого числа считается ошибка в этом случае, и последняя строка также должна заканчиваться новой строкой.

Это не проверяет, есть ли что-то после теоретического конца, вы можете сделать несколько способов.

Также в ваш пример идентификатор вершины, являющийся первым номером в каждой паре, представляет собой последовательные числа 1, 2 ... в предложениях, прежде чем я не проверяю, что даже это легко проверить vertex == verticesRank+1. Если это правило, зачем давать пару значений даром, когда достаточно только второго числа?

...