【问题标题】:segmentation fault when rewinding my file pointer倒带我的文件指针时出现分段错误
【发布时间】:2020-09-28 03:33:17
【问题描述】:

当我的文件指针第二次倒带时,会导致段错误。我不知道为什么。我将在顶部包含有问题的 main 及其下面的所有代码。

int main(void){
    // creating the file pointer
    FILE *fptr = fopen("input-machine-problem-1.txt", "r");
    if (fptr == NULL) {
        printf("Error! opening file");
        return 0;
    }

    int edges;
    int vertices;
    int* edgesPtr = &edges;
    int* verticesPtr = &vertices;
    getNumberOfVerticesAndEdges(fptr, verticesPtr, edgesPtr);

    LinkedList arrayOfLinkedLists[vertices];

    int x, y;
    for(int i = 0; i < vertices; i++){ 
        if(fptr == NULL){
            return 0;
        }
        rewind(fptr);
        for(int j = 0; j < edges; j++){
            
            printf("%d: ", j);
            fscanf (fptr, "%d %d", &x, &y);    
            printf ("%d %d ", x, y);
            if(i == x){
                push(arrayOfLinkedLists[i], y);
            } else if(i == y){
                push(arrayOfLinkedLists[i], x);
            }
            printf("**\n");
        }
    }

    // printAdjacencyLists(arrayOfLinkedLists, vertices);
    fclose (fptr); 
}

如果您想复制和粘贴整个文件:

#include <stdio.h>
#include <stdlib.h>

typedef struct node{
    int vertexNumber;
    struct node *next;
} Node;

typedef struct linkedList{
    Node* head;
    int size;
} LinkedList;

void getNumberOfVerticesAndEdges(FILE* fp, int* vertices, int* edges);
void push(LinkedList linkedList, int vertex);
Node* createNode(int vertexNumber);
void printAdjacencyLists(LinkedList* arrayOfLinkedLists, int vertices);

int main(void){
    // creating the file pointer
    FILE *fptr = fopen("input-machine-problem-1.txt", "r");
    if (fptr == NULL) {
        printf("Error! opening file");
        return 0;
    }

    int edges;
    int vertices;
    int* edgesPtr = &edges;
    int* verticesPtr = &vertices;
    getNumberOfVerticesAndEdges(fptr, verticesPtr, edgesPtr);

    LinkedList arrayOfLinkedLists[vertices];

    int x, y;
    for(int i = 0; i < vertices; i++){ 
        if(fptr == NULL){
            return 0;
        }
        rewind(fptr);
        for(int j = 0; j < edges; j++){
            
            printf("%d: ", j);
            fscanf (fptr, "%d %d", &x, &y);    
            printf ("%d %d ", x, y);
            if(i == x){
                push(arrayOfLinkedLists[i], y);
            } else if(i == y){
                push(arrayOfLinkedLists[i], x);
            }
            printf("**\n");
        }
    }

    // printAdjacencyLists(arrayOfLinkedLists, vertices);
    fclose (fptr); 
}

void push(LinkedList linkedList, int vertex){
    Node* newNode = createNode(vertex);

    Node* cur = linkedList.head;
    Node* prev = cur;
    if(cur == NULL){
        linkedList.head = newNode;
        return;
    }
    while(newNode->vertexNumber > cur->vertexNumber){
        prev = cur;
        cur = cur->next;
    }
    newNode->next = cur;
    prev->next = newNode;


}

Node* createNode(int vertexNumber){
    Node* newNode = malloc(sizeof(Node));
    if(!newNode){
        return NULL;
    }
    newNode->vertexNumber = vertexNumber;
    newNode->next = NULL;
    return newNode;
}

void getNumberOfVerticesAndEdges(FILE* fp, int* vertices, int* edges){
    if (fp == NULL) {
        printf("Error! opening file");
        return;
    } 

    *vertices = 0;
    *edges = 0;
    while(1){
        int x, y;

        fscanf(fp, "%d %d^\n", &x, &y);

        if(x > *vertices){
            *vertices = x;
        } if (y > *vertices){
            *vertices = y;
        }

        *edges = (*edges) + 1;

        if(feof(fp)) { 
            return;
        }
    }
}

void printAdjacencyLists(LinkedList* arrayOfLinkedLists, int vertices){
    for(int i = 0; i < vertices; i++){
        printf("\n%d:  ", i);
        if(arrayOfLinkedLists[i].head == NULL){
            return;
        }
        Node* cur = arrayOfLinkedLists[i].head;
        while(cur != NULL){
            printf("%d --> ", cur->vertexNumber);
            cur = cur->next;
        }
    }
}

【问题讨论】:

  • 您在使用xy 未能检查返回 of fscanf() 并且在函数结束之前不要检查流状态。你写Why is while ( !feof (file) ) always wrong? 的方式略有不同。您还可以从fscanf(fp, "%d %d^\n", &amp;x, &amp;y); 中删除'\n',因为它没有按照您的想法进行操作,并且"%d" 转换说明符无论如何都会忽略前导空格。
  • 没有输入文件,没有人可以测试代码。

标签: c pointers segmentation-fault rewind


【解决方案1】:

您需要通过返回 fscanf() 来控制您的读取循环,例如

void getNumberOfVerticesAndEdges(FILE* fp, int* vertices, int* edges)
{
    int x, y;
    
    if (fp == NULL) {
        printf("Error! opening file");
        return;
    } 

    *vertices = 0;
    *edges = 0;
    while (fscanf(fp, "%d %d", &x, &y) == 2) {
        if(x > *vertices){
            *vertices = x;
        } if (y > *vertices){
            *vertices = y;
        }

        *edges = (*edges) + 1;
    }
}

注意:格式字符串中不需要^\n

这可确保您仅在 xy 中的值具有有效值时才使用它们。正如您所写,xy 或两者都可能导致转换失败(matchinginput 失败)并且您仍然使用这些值进行比较并根据结果将值分配给*verticies,但不保证xy 有效。

此外,正如您所写的那样,*edges = (*edges) + 1;fscanf() 失败之后执行,在您检查导致edges 的流状态太多时执行。

除非您检查返回,否则您无法正确使用任何输入功能。如果您还有其他问题,请告诉我。您的代码可能还有其他问题,但一旦读取失败 - 这可能是您的第一个主要问题。

下一个 SegFault

您的下一个 SegFault 位于 push() 此处:

while(newNode->vertexNumber > cur->vertexNumber){
    prev = cur;
    cur = cur->next;
}

在取消引用 cur-&gt;vertexNumber 之前,您不会通过检查 cur == NULL 来检查列表末尾。每次都会这样做。您可以使用以下方法修复它:

while (cur && newNode->vertexNumber > cur->vertexNumber) {

“*”去哪儿了?

在整个代码中,您将间接引用附加到 type 而不是 variable。可能具有误导性。为什么?

int* a, b, c;

您当然没有声明三个指向int 的指针。相反,您将 a 声明为指向 intbc 的简单整数。

int *a, b, c;

说清楚了。

显然,编译器并不关心,它忽略了'*' 和变量名之间的空格,所以你所拥有的并没有错——这更多是人为因素/可读性问题。

其他问题

如果您不使用size,请将其从以下位置删除:

typedef struct linkedList{
    Node* head;
    int size;
} LinkedList;

此外,由于edgesvertices 不能为负数,sizexy 也不能为负数,因此将它们设为size_t 而不是int。您将 type 与变量 use 匹配,并且在 x86_64 上您会获得额外的 4 字节范围。

对代码采用另一种方法

理想情况下,您只想读取一次数据文件。如果您动态分配指针而不是为LinkedList arrayOfLinkedLists[vertices]; 使用 VLA,则可以这样做,我将把它的实现留给您。解决上述问题并稍微清理一下您的 push() 函数,您可以执行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node{
    size_t vertexNumber;
    struct node *next;
} Node;

typedef struct linkedList{
    Node *head;
    size_t size;
} LinkedList;

Node *createNode (size_t vertexNumber)
{
    Node *newNode = malloc (sizeof *newNode);
    
    if (!newNode) {
        perror ("malloc-newNode");
        return NULL;
    }
    
    newNode->vertexNumber = vertexNumber;
    newNode->next = NULL;
    
    return newNode;
}

int getNumberOfVerticesAndEdges (FILE *fp, size_t *vertices)
{
    size_t edges = 0, x, y;
    
    *vertices = 0;
    
    while (fscanf(fp, "%zu %zu", &x, &y) == 2) {
        if (x > *vertices)
            *vertices = x;
        if (y > *vertices)
            *vertices = y;

        edges += 1;
    }
    
    return edges;
}

/* add nodes in order of vertexNumber to each list */
Node *push (LinkedList *list, size_t vertex)
{
    Node *newNode = createNode(vertex);         /* create new node/initialize */
    
    if (!newNode)                               /* validate node */
        return NULL;
    
    list->size += 1;                            /* node allocated, increment count */
    
    if (!list->head) {                          /* if 1st node, node is head/tail */
        list->head = newNode;
        return list->head;
    }
    
    Node **pp = &list->head,                    /* iterate with address of pointer */
          *p  = list->head;                     /* and pointer to node */
    
    while (p) { /* loop over each node */
        if (vertex < p->vertexNumber) {         /* if new vertext less than current */
            *pp = newNode;                      /* replace current with new */
            newNode->next = p;                  /* set new->next to current */
            return newNode;
        }
        pp = &p->next;                          /* advance to next node */
        p = p->next;
    }
    
    return *pp = newNode;                       /* insert at end */
}

void printAdjacencyLists (LinkedList *arrayOfLinkedLists, size_t vertices)
{
    for (size_t i = 0; i < vertices; i++) {
        printf ("\n%zu:  ", i);
        
        if (arrayOfLinkedLists[i].head == NULL)
            return;
        
        Node *cur = arrayOfLinkedLists[i].head;
        
        while (cur){
            printf("%zu --> ", cur->vertexNumber);
            cur = cur->next;
        }
    }
    putchar ('\n');     /* tidy up with newline */
}

void freelists (LinkedList *a, size_t v)
{
    for (size_t i = 0; i < v; i++) {
        Node *node = a[i].head;
        while (node) {
            Node *victim = node;
            node = node->next;
            free (victim);
        }
    }
}

int main (int argc, char **argv){
    
    size_t edges = 0,
        vertices = 0,
        x, y;
    /* open filename provides as 1st argument, use default if none provided */
    FILE *fptr = fopen (argc > 1 ? argv[1] : "input-machine-problem-1.txt", "r");
    
    if (!fptr) {
        perror ("fopen-fptr");
        return 1;
    }

    if (!(edges = getNumberOfVerticesAndEdges (fptr, &vertices))) {
        fputs ("error: failed to read edges.\n", stderr);
        return 1;
    }
    
    /* initialize array of lists all zero/NULL */
    LinkedList arrayOfLinkedLists[vertices];
    memset (arrayOfLinkedLists, 0, sizeof arrayOfLinkedLists);

    for (size_t i = 0; i < vertices; i++) { 
        if (!fptr) {
            return 1;
        }
        rewind(fptr);
        for (size_t j = 0; j < edges; j++) {
            
            printf("%zu: ", j);
            if (fscanf (fptr, "%zu %zu", &x, &y) != 2) {
                fprintf (stderr, "error reading vertex: %zu, edge: %zu\n", i, j);
                return 1;
            }   
            printf ("%zu %zu ", x, y);
            
            if (i == x) {
                if (!push (&arrayOfLinkedLists[i], y))
                    return 1;
            }
            else if (i == y) {
                if (!push (&arrayOfLinkedLists[i], x))
                    return 1;
            }
            printf("**\n");
        }
    }
    fclose (fptr);

    printAdjacencyLists (arrayOfLinkedLists, vertices);
    
    freelists (arrayOfLinkedLists, vertices);
}

上面还包括一​​个freelists() 函数,用于free() 您为列表分配的所有内存。始终确保您正在跟踪和释放您分配的内存。这样,在分配 main() 以外的内容时,您不会造成内存泄漏。

输入/输出示例

使用示例顶点执行代码将产生以下输出:

$ ./bin/getverticies dat/edgelist.txt
0: 0 1 **
1: 2 3 **
2: 3 2 **
3: 1 0 **
0: 0 1 **
1: 2 3 **
2: 3 2 **
3: 1 0 **
0: 0 1 **
1: 2 3 **
2: 3 2 **
3: 1 0 **

0:  1 --> 1 -->
1:  0 --> 0 -->
2:  3 --> 3 -->

注意:文件名现在可以作为第一个参数传递给程序)

【讨论】:

  • 谢谢,这很有意义,我修复了我的功能。虽然这有帮助,但我相信 seg 错误源于 main()。我注释掉了 getNumberOfVerticesAndEdges() 并对测试值进行了硬编码,段错误仍然存​​在。您是否在我的 main() 中看到任何问题。此外,如果有帮助,输入文件很简单: "%d %d\n%d %d\n..." 所以基本上是以空格分隔的整数,然后是新行。另外,我知道推送调用中发生了段错误,因为如果我将它们注释掉,我就可以扫描所有整数并将它们打印出来
  • 让我看看。我将在几个小时内有时间,并将完成其余的代码。如果您有可以发布的示例数据,这将有助于确保我可以重现您所看到的确切问题。
猜你喜欢
  • 2020-02-18
  • 2018-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多