我正在尝试编写和使用链表。当试图将列表打印到文件时,第一个字符串被链接到最后一个节点,这会导致segfault。
我试过调试,但没有成功。
它只在使用printListToFile(...)
和readstl(...)
时发生。
代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lists_c.h"
#define test "ijm digidimdimadam jjsklva /s4tt nmjam nla kookaracha la kookarachan"
/*a method that creates a "blank" node, declares a the next node and points it to NULL, the char array is already initialized.*/
struct Node *makeNode();
struct Node *makeFullNode(struct Node *Next, char *Ptr);
struct Node *readFile(char *path);
struct Node *readstl(char*);
void printList(struct Node *head);
void insertToList(struct Node *node, char *str);
void printListToFile(char *path, struct Node *head);
int main(int argc, char *argv[])
{
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
printf("this is mmn 23 Q3, a func that stores a file in a linked list and then prints it.n");/*
printf("%sn",argv[1]);
if (argc == 2) { */
head = readFile("tester1.txt");
printList(head);
printListToFile("test.tmp", head);
insertToList(head->next, test);
printf("head");
free(head);
/*}
else if (argc > 2) {
printf("Too many arguments supplied.n");
} else {
printf("One argument expected.n");
}*/
return 0;
}
struct Node *makeNode()
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
if (node == NULL) {
printf("memory allocation failedn");
return NULL;
}
node->next = NULL;
return node;
}
/*a method that creates a node with all values, declares a the next node and points it to the next node recieved
and changes the char array to the one recieved.*/
struct Node *makeFullNode(struct Node *Next, char Ptr[])
{
struct Node *node;
node = (struct Node *)malloc(sizeof(struct Node));
node->next = (struct Node *)malloc(sizeof(struct Node));
node->ptr[NICE] = Ptr[NICE];
node->next = Next;
return node;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readFile(char *path)
{
FILE *fptr;
struct Node *curr, *head;
curr = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL || head == NULL) {
printf("memory allocation failedn");
return NULL;
}
curr = head;
fptr = fopen(path,"r");
if (fptr == NULL) {
printf("error - failed to open filen");
exit(0);
return NULL;
}
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
curr = curr->next;
}
if(ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read filenthis is what we got so farn");
}
printf("file succesfully readn");
fclose(fptr);
free(curr);
return head;
}
/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readstl(char *path)/*!!!problem!!!*/
{
FILE *fptr;
int i, len;
struct Node *head;
head = (struct Node *)malloc(sizeof(struct Node));
fptr = fopen("readstrtofile.tmp", "w");
if (fptr == NULL) {
printf("error - failed to open filen");
exit(0);
return NULL;
}
len = strlen(path);
for (i = 0; i < len && fputc(*(path + i), fptr) != EOF; i++);
if (ferror(fptr))/*checking if the loop ended for the right reason*/
{
printf("error - failed to read into filenthis is what we got so farn");
}
fclose(fptr);
head = readFile("readstrtofile.tmp");
remove("readstrtofile.tmp");
return head;
}
/*a method that prints the recieved list depending on the list to have the equal length rows.
as specified in mmn 12 tab creating uneven rows is acceptable therefor when ever there is tab in the file
the rows will appear uneven as to tab takes a place of one char but prints to 8 blank spaces in ubuntu */
void printList(struct Node *head)
{
struct Node *curr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (head == NULL) {
printf("empty listn");
return;
}
if (curr==NULL) {
printf("memory allocation failedn");
return;
}
printf("this is the list printed nicelyn");
curr = head;
printf("%sn", curr->ptr);
while (curr->next != NULL) {
curr = curr->next;
printf("%sn", curr->ptr);
}
printf("n/********************/n");
}
/* a method that creates a new file named path and prints a list to it */
void printListToFile(char *path,struct Node *head)/*!!!problem!!!*/
{
struct Node *curr;
char c;
int i;
FILE *fptr;
curr = (struct Node *)malloc(sizeof(struct Node));
if (curr == NULL) {
printf("memory allocation failedn");
exit(0);
}
curr = head;
fptr = fopen(path, "w+");
if (fptr == NULL) {
printf("error - failed to open filen");
exit(0);
}
if (head == NULL) {
printf("empty listn");
exit(0);
}
printf("this is the file %s printed nicelyn",path);
curr = head;
while (curr->next != NULL) {
printf("new node -> ptr -> %sn",curr->ptr);
/*if(sizeof(curr->ptr)/sizeof(char)<=NICE)
{*/
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
printf("puting %s to file %sn",curr->ptr,path);
curr = curr->next;
printf("bolilin");
/*}
else
{
printf("lilibon");
break;
}*/
}
printf("n/********************/n");
}
/* a method that recievs a string turns it into a list and inserts it into another list */
void insertToList(struct Node *node, char *str)
{
struct Node *tail, *head;
tail = (struct Node *)malloc(sizeof(struct Node));
head = (struct Node *)malloc(sizeof(struct Node));
if (tail == NULL || head == NULL) {
printf("memory allocation failedn");
return;
}
head = readstl(str);/*reading the string to a node*/
printList(head);
printf("n/***********in insert*********/n");
tail = head;
while (tail->next) {
tail = tail->next;
}/*getting tto the last node to connect it*/
strcpy(tail->ptr, node->next->ptr);/*connecting the lists*/
tail->next = node->next->next;
strcpy(node->ptr, head->ptr);
node->next = head->next;
printf("inserted string successfullyn");
}
/* a method that returns the size of the list*/
unsigned int sizeOfList(struct Node *head)
{
struct Node *tmp;
int size;
if (!(head))
return 0;
size = 1;
tmp = (struct Node *)malloc(sizeof(struct Node));
tmp = head;
while ((tmp = tmp->next))
size++;
return size;
}
头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NICE 80
#define debug "n/****************/n"
/*the node structure of a the list which contains a string the size we choose is nice
to print by and a pointer to the next node in the list. */
struct Node {
char ptr[NICE];
struct Node *next;
};
/*makeNode - a method that returns a newely created node and sets all values to NULL values.*/
struct Node *makeNode();
/*makeFullNode - a method that return a newely created node with values set to params as listed below.
@param Next - tho ptr to the next node desired.
@param Ptr - the string that will go into the node ptr.*/
struct Node *makeFullNode(struct Node *Next, char *Ptr);
/*readFile - a method that reads a file into a linked list returning the head to that list.
it reads the file using fgets and a const to decide what size the node strings should be.
@param path - the name of the file to open.
@return the head of the list.*/
struct Node *readFile(char *path);
/*readstl - a method that reads a string into a linked list returning the head to that list.
it prints the list to a tmp file then reads the file using readFile.
@param path - the string to read.
@return the head of the list.*/
struct Node *readstl(char*);
/*printList - a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
@param head - the head of the linked list.*/
void printList(struct Node *head);
/*insertToList - a method that inserts a string into list.
it creates a new list using readstl the connects the nodes using the basic method.
@param node - the node to override.
@param str - the string to insert.*/
void insertToList(struct Node *node, char *str);
/*a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
@param head - the head of the linked list.*/
void printListToFile(char *path,struct Node *head);
/*sizeOfList - a method that returns how many node are in the list.
it goes in a while loop incresing counter by 1 each iteration.
@param head - the head of the list to measure.
@return the size of the list.*/
unsigned int sizeOfList(struct Node *head);
我想是这一行:
for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);
如果一切顺利,为什么fputc
会返回EOF?它将尝试在ptr
数组后面写入字符。来自fputc
:的手册页
fputc((、putc((和putchar((返回以无符号字符形式写入的字符,并在出错时转换为int或EOF。
这意味着,只要fputc
不返回错误代码,循环就会写入。但您可能想要的是编写80个字符(NICE
不是一个好的常量名称(或strlen(curr->ptr)
个字符。假设基于您的readFile函数,您希望这两件事都作为限制。我建议将这一行改写为:
int len = strnlen(curr->ptr, 80);
if (fwrite(curr->ptr, 1, len, fptr) < 0) {
printf("error writing file");
}
或者如果字符串总是空终止:
if (fputs(curr->ptr, fptr) < 0) {
printf("error writing file");
}
此外,ptr
不是一个好的数组名称。经过一段时间,试图理解代码时,它可能会让人们甚至你感到困惑。更好的名称应该是value
或text
(即使是arr
也会更好,因为它不是指针(。
在readFile
中,您有一个循环,在其中读取一行并将其放入curr->ptr
,然后创建一个新的curr
并将其链接到以前的curr
。
这会在列表末尾创建一个额外的空curr
,您不需要它,因此稍后可以释放它。不幸的是,上一个节点的next
指针仍然指向刚刚释放的空节点。
在不重新构造循环的情况下修复此问题的最简单方法是保留前一个节点的记录,类似于以下内容:
struct Node* prev = NULL;
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
curr->next = makeNode();
prev = curr;
curr = curr->next;
}
free(curr);
if (prev != NULL)
{
prev->next = NULL;
}
else
{
head = NULL; // For the empty file case. head == curr in this case
}
// The other clean up stuff