简体   繁体   English

倒带文件指针时出现分段错误

[英]segmentation fault when rewinding my file pointer

When my file pointer hits it's second rewind, it causes a seg fault.当我的文件指针命中它的第二次倒带时,它会导致段错误。 I have no clue why.我不知道为什么。 I'll include the main that is problematic at the top and all the code below it.我将在顶部包含有问题的主要内容及其下方的所有代码。

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); 
}

The whole file in case you want to copy and paste:如果您想复制和粘贴整个文件:

#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;
        }
    }
}

You need to control your read loop with the return of fscanf() , eg您需要通过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;
    }
}

( note: there is no need for ^\\n in your format string) 注意:格式字符串中不需要^\\n

This ensures that you only use the values in x and y when they hold a valid value.这确保您仅在xy的值持有有效值时才使用它们。 As you have written it, either x or y or both can fail the conversion (with a matching or input failure) and you still use those values in comparison and depending on the result, assign the values to *verticies without any guarantee that x or y are valid.正如您所写的, xy或两者都可能导致转换失败(匹配输入失败),并且您仍然使用这些值进行比较,并根据结果将值分配给*verticies而不保证xy是有效的。

Further, as you have it written, *edges = (*edges) + 1;此外,正如你所写的, *edges = (*edges) + 1; is executed after fscanf() fails and before you check the stream state leading to edges being off-by-one too many.fscanf()失败之后和检查导致edges为一的边太多的流状态之前执行。

You can't use any input function correctly unless you check the return .除非您检查 return ,否则您无法正确使用任何输入函数。 Let me know if you have further questions.如果您还有其他问题,请告诉我。 Your code may have other issues, but once the read failed -- that is your likely first major problem.您的代码可能有其他问题,但一旦读取失败——这可能是您的第一个主要问题。

Next SegFault下一段故障

Your next SegFault is in push() here:您的下一个 SegFault 位于push()

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

You don't check for end-of-list by checking if cur == NULL before dereferencing cur->vertexNumber .在取消引用cur->vertexNumber之前,您不会通过检查cur == NULL来检查列表cur->vertexNumber That will do it every time.每次都会这样做。 You can fix it with:您可以使用以下方法修复它:

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

Where Does The '*' Go? “*”在哪里?

Throughout your code you are attaching the indirection reference to the type instead of the variable .在整个代码中,您将间接引用附加到类型而不是变量 The can be misleading.可能会产生误导。 Why?为什么?

int* a, b, c;

Above you are certainly not declaring three pointers to int .上面你肯定没有声明三个指向int指针。 Instead, you declare a as a pointer to int and b and c as simple integers.相反,您a a 声明为指向int的指针,将bc为简单整数。

int *a, b, c;

Makes that clear.说清楚了。

Obviously, the compiler doesn't care, it ignores whitespace between '*' and the variable name, so what you have is not wrong -- this is more a human factors/readability issue.显然,编译器不在乎,它忽略了'*'和变量名之间'*'空格,所以你所拥有的并没有错——这更多是一个人为因素/可读性问题。

Other Issues其他事宜

If you are not using size , remove it from:如果您不使用size ,请将其从:

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

Further, since edges and vertices cannot be negative, nor can size or x or y , make them size_t instead of int .此外,由于edgesvertices不能为负, sizexy也不能为负,因此将它们size_t而不是int You match the type to the variable use, and on x86_64 you get an additional 4-bytes of range.您将type与变量使用相匹配,在 x86_64 上,您将获得额外的 4 字节范围。

Taking Another Approach To Your Code对你的代码采取另一种方法

Ideally, you want to only read your data file once.理想情况下,您只想读取数据文件一次。 You can do so if you dynamically allocate pointers instead of using a VLA for LinkedList arrayOfLinkedLists[vertices];如果您动态分配指针而不是为LinkedList arrayOfLinkedLists[vertices];使用 VLA,则可以这样做LinkedList arrayOfLinkedLists[vertices]; I'll leave the implementation of that to you.我会把它的实现留给你。 Addressing the issues above and cleaning up your push() function a bit, you could do something like the following:解决上述问题并稍微清理一下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);
}

Also included above is a freelists() function to free() all the memory you allocate for your lists.上面还包括一​​个freelists()函数,用于free()您为列表分配的所有内存。 Always ensure you are tracking and freeing the memory you allocate.始终确保您正在跟踪和释放您分配的内存。 That way when allocating in other than main() you are not creating memory-leaks.这样,在分配main()以外的内容时,您不会造成内存泄漏。

Example Made Up Input/Output示例组成输入/输出

Exercising the code with example vertex would result in the following output:使用示例顶点执行代码将产生以下输出:

$ ./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 -->

( note: the filename can now be passed as the first argument to the program) 注意:文件名现在可以作为第一个参数传递给程序)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM