c - 倒带我的文件指针时出现分段错误
问题描述
当我的文件指针第二次倒带时,它会导致段错误。我不知道为什么。我将在顶部包含有问题的 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;
}
}
}
解决方案
您需要通过返回来控制您的读取循环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
格式字符串中不需要)
这可确保您仅在它们包含有效值时使用这些值x
。y
正如您所写的那样,其中一个x
或y
两个都可能使转换失败(匹配或输入失败),并且您仍然使用这些值进行比较,并根据结果分配这些值,*verticies
而不保证x
或y
有效。
此外,正如您所写的那样,在失败*edges = (*edges) + 1;
之后执行fscanf()
,在您检查流状态之前执行,这会导致edges
太多错误。
除非您检查 return,否则您无法正确使用任何输入功能。如果您还有其他问题,请告诉我。您的代码可能还有其他问题,但是一旦读取失败 - 这可能是您的第一个主要问题。
下一个 SegFault
您的下一个 SegFault 在push()
这里:
while(newNode->vertexNumber > cur->vertexNumber){
prev = cur;
cur = cur->next;
}
您不会通过cur == NULL
在取消引用之前检查 if 来检查列表末尾cur->vertexNumber
。每次都会这样做。您可以使用以下方法修复它:
while (cur && newNode->vertexNumber > cur->vertexNumber) {
'*' 去哪儿了?
在整个代码中,您将间接引用附加到类型而不是变量。可能具有误导性。为什么?
int* a, b, c;
上面你肯定没有声明三个指向int
. 相反,您将其声明a
为指向和的指针,int
以及b
作为c
简单整数。
int *a, b, c;
说明了这一点。
显然,编译器不在乎,它忽略'*'
了变量名和变量名之间的空格,所以你所拥有的并没有错——这更多是人为因素/可读性问题。
其他问题
如果您不使用size
,请将其从以下位置删除:
typedef struct linkedList{
Node* head;
int size;
} LinkedList;
此外,因为edges
andvertices
不能是负数,也不能size
or x
or y
,使它们size_t
代替int
. 您将type
与变量 use 匹配,并且在 x86_64 上您会获得额外的 4 字节范围。
对代码采取另一种方法
理想情况下,您只想读取一次数据文件。如果您动态分配指针而不是使用 VLA,则可以这样做,因为LinkedList arrayOfLinkedLists[vertices];
我将把它的实现留给您。解决上述问题并稍微清理一下您的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 -->
(注意:文件名现在可以作为第一个参数传递给程序)
推荐阅读
- google-apps-script - 应用脚本基于时间的触发器多次执行
- google-apps-script - 使用脚本编辑器根据特定单元格值自动隐藏“非空”行
- php - Apple 登录二手零售店
- node.js - 将云功能更新为合适的 Node js 版本
- sails.js - 覆盖 Sails.js 水线拦截 Find 方法
- terraform - local-exec 问题并将值传递给它
- c# - 将小数四舍五入到小数点后 2 位
- python - 从高斯分布采样
- arrays - 尝试根据用户输入应用过滤器时无法读取未定义的属性“包含”
- javascript - 角度检测用户是否来自 webview