我的gdb调试器出现问题,每次尝试运行程序时,调试器都会在我使用“fgets”()的行中发出以下错误:_IO_fgets(buf = 0x7fffffffe330“P \ 343 \ 377 \ 377 \ 377 \ 177“,n = 2,fp = 0x0)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct _node {
int value ;
struct _node * next ;
} node ;
void print_avg(node * head, int n)
{
int sum = 0 , i = 0;
node * p = head ;
for (i = 0 ; i < n ; i++) {
sum += p->value ;
p = p->next ;
}
printf("%f\n", ((float)sum / (float)n)) ;
}
int get_nums(node ** head)
{
int n = 1 ;
char line[4] ;
while (fgets(line, sizeof(line), stdin) != NULL) {
//strtok(line, "\n") ;
node * curr ;
curr = (node *) malloc(sizeof(node)) ;
curr->value = atoi(line) ;
curr->next = *head ;
*head = curr ;
n++ ;
}
return n ;
}
int main()
{
int n ;
node * head = NULL;
n = get_nums(&head) ;
print_avg(head, n) ;
return 0 ;
}
我不知道我的fgets()有什么问题。有人有想法吗?
答案 0 :(得分:1)
您对fgets
的使用看起来对我来说是正确的,但您的代码中还有另一个问题:n
已关闭。
替换
int n = 1;
通过
int n = 0;
因为最初列表包含0个元素,而不是1个元素。
但无论如何这更好:
您应该在for
循环中使用此功能。
for (node * p = head; p != NULL; p = p->next)
该列表由NULL
字段中的next
指针终止。因此,您应检查此条件,而不是测试元素数量。
答案 1 :(得分:0)
使用Valgrind我得到了
Access not within mapped region at address 0x0
at 0x4006D8: print_avg (main.c:16)
如果p为NULL,则问题是指令sum += p->value
。
p是NULL因为head是NULL因为int get_nums(node * head)
创建了指向head的指针的副本所以当你做head = curr ;
时,你实际上是将指针的值存储到副本中所以当你返回main,第一个头指针仍然是NULL并且你有内存泄漏,因为你无法释放你分配的内存(因为指针现在丢失了)。
这是您需要的实际工作代码
#include <stdio.h>
#include <string.h>
include <stdlib.h>
typedef struct _node {
int value ;
struct _node * next ;
node ;
void print_avg(node ** head, int n)
int sum = 0 , i = 0;
node *p = *head ;
//better check p value here to avoid segmentation fault
for (i = 0 ; i < n && p!=NULL; i++) {
sum += p->value ;
p = (*head)->next ;
free(*head);
*head = p;
}
printf("%f\n", ((float)sum / (float)n)) ;
int get_nums(node ** head)
int n = 0 ;
char line[4] ;
while (fgets(line, sizeof(line), stdin)) {
//strtok(line, "\n") ;
node * curr ;
curr = (node *) malloc(sizeof(node)) ;
curr->value = strtol(line,NULL,10) ;
curr->next = *head ;
*head = curr ;
n++ ;
}
return n ;
int main()
int n ;
node * head = NULL;
//here we pass the address of head pointer so that the function will be able to set it
n = get_nums(&head) ;
//here we pass the address of head pointer so that the function will be able to free your list of pointers
print_avg(&head, n) ;
return 0 ;
超过n必须从int get_nums(node ** head)
函数
问候!
@Walz在这种情况下,您需要将指针传递给指针,否则 如果 你释放了打印功能里面的节点,从print_avg函数之后的函数外部的头指针不会指向你的列表的右头。 现在让我们说我有一个指向MY_LIST的指针A然后我在print_avg中复制指针A来处理MY_LIST,因为我释放MY_LIST中的节点并且我从print_avg返回ponter A没有改变!因此它将指向前一个头(已被释放),因此如果我尝试通过指针A访问它,则会出现一个分段错误。
如果您确定在程序中不再需要它们,则应始终释放已分配的资源。由于我们正在访问列表,因此释放列表的最有效方法是逐节点释放它,因为您已经使用该值来计算平均值但是您可以在以后随时释放它们,可能在另一个函数中。
最后,由于你的主要目的,释放资源在这里并不那么重要,但它应该像你习惯在松开指针之前释放已分配的资源。想象一下,您正在编写一个多线程服务器,每个连接甚至会丢失一个字节。迟早你会失去记忆。
问候!
@MasterGL我不知道这是不是你的问题,但是如果我在Eclipse中运行调试器,如果我在执行fgets指令时“步入”我也会收到一些错误(也许调试器没有有fgets源代码显示)。我做了“Step over”,我只使用“Step Into”进入我的功能。效果很好