我的代码再次出现问题
我想fscanf
result.txt到带有链表的结构,但它不起作用;
我认为必须使用简单的链表;
问题是:程序只写第一行,但没有别的。
result.txt格式:
point name (for examples)
623 john
457 peter
312 chuck
etc.
代码:
#include <stdio.h>
#include <stdlib.h>
typedef struct ranklist {
int point;
char* name;
struct ranklist *next;
} ranklist;
int how_many_records(FILE *fp){
char ch;
int line=0;
int status;
rewind(fp);
while((status=fscanf(fp, "%*d %*[^\n]%c", &ch))==1)
++line;
if(status != EOF){
++line;
}
rewind(fp);
return line;
}
int how_many_letter(FILE *fp){
int letter = 0;
long pos = ftell(fp);
//fscanf(fp, " %*[^\n]%n", &letter);
fscanf(fp, " %*s%n", &letter);
fseek(fp, pos, SEEK_SET);
return letter;
}
int main(void){
FILE *fp = fopen("result.txt","r");
int name_length;
int lines = how_many_records(fp);
ranklist *r = malloc(lines * sizeof(*r));
ranklist *first = r;
for ( r=first ;r != NULL; r = r->next){
fscanf(fp, "%d", &(r->point));
name_length = how_many_letter(fp);
r->name = malloc(name_length + 1);
fscanf(fp,"%s", r->name);
}
fclose(fp);
for ( r=first ;r != NULL; r = r->next){
printf("%d %s\n", r->point, r->name);
}
free(r);
return 0;
}
答案 0 :(得分:0)
fscanf(fp, "%d", &r[y].point);
此处,y
未初始化。
您需要将y = 0
或IMO更好地用于&(r->point)
[同样适用于r[y].name
]
建议:更好地阅读和解析整行以使用fgets()
答案 1 :(得分:0)
创建列表时遇到了多个问题。
让我们从循环开始:
for ( r=first ;r != NULL; r = r->next){
循环中的 无处会初始化r->next
,因此在第一次迭代后,您将y
指向完全随机的内存,从而导致undefined behavior。
正如另一个答案中所提到的,你不要初始化变量y
,这是导致未定义行为的另一个原因。
您还更改 r
,因此r
不会指向您分配的原始内存,因此r[y]
是未定义行为的第三个原因。< / p>
在循环之后,使用修改后的指针free
调用y
,这也会导致未定义的行为。并且你不会释放你在循环中分配的名字,所以也有多个内存泄漏。
根本不需要预先分配节点,只需在需要时进行分配。
像
这样的东西ranklist *head = NULL;
FILE *fp = fopen(...);
// Read the file and create the list
char buffer[256];
while (fgets(buffer, sizeof(buffer), fp) != NULL)
{
ranklist *node = malloc(sizeof(ranklist));
node->name = malloc(strlen(buffer)); // Will allocate a little more than needed
sscanf(buffer, "%d %s", &node->point, node->name);
node->next = head;
head = node;
}
// Print the list
for (ranklist *n = head; n != NULL; n = n->next)
{
printf("%d %s\n", n->point, n->name);
}
// Free the list
while (head != NULL)
{
// Unlink the first node in the list
ranklist *n = head;
head = n->next;
// And free it
free(n->name);
free(n);
}
上面的代码没有任何错误检查,在为名称分配空间时也有一些开销,但它是安全的,它不会处理不切实际的长名称,并且列表实际上是一个堆栈(最后读取的项目将在列表中排在第一位。)
使用fgets
读取缓冲区中名称长度的函数:
size_t get_name_length(char *buffer)
{
// Since the buffer was read with `fgets` we need to get rid
// of the newline at the end, if it's there
size_t length = strlen(buffer);
if (buffer[length - 1] == '\n')
buffer[length - 1] = '\0'; // "Remove" by terminating the string
// Find the space dividing the point and the name
char *space = strchr(buffer, ' ');
// Just in case there are multiple whitespace characters in the string
while (*space != '\0' && isspace(*space))
++space;
// Now `space` points to the first non-space letter in the name
// (or to the string terminator, if there's no name
// Then length of the name is the remainder of the string
return strlen(space);
}
答案 2 :(得分:0)
FILE *fp = fopen("result.txt","r");
int name_length;
//Just create a link if you use as an array
//int lines = how_many_records(fp);
//ranklist *r = malloc(lines * sizeof(*r));
ranklist *first=NULL, *curr, *r;
int point;
while(1==fscanf(fp, "%d", &point)){
r = malloc(sizeof(*r));//allocate one record
r->next = NULL;
r->point = point;
name_length = how_many_letter(fp);
r->name = malloc(name_length + 1);
fscanf(fp, "%s", r->name);
//make link
if(first == NULL)
first = curr = r;
else
curr = curr->next = r;
}
fclose(fp);
for (r = first; r != NULL; r = r->next){
printf("%d %s\n", r->point, r->name);
}
for (r = first; r != NULL; ){
ranklist *tmp = r->next;//Save next for free(r)
free(r->name);
free(r);
r = tmp;
}
//output the list
void print(ranklist *first){
while(first != NULL){
printf("%d %s\n", first->point, first->name);
first = first->next;
}
}