如果我有一个包含内容的文件流
123 1234
1223 124235
21432 325
在我的程序中,我逐行读取文件,并将每行的第一个目标存储到我的列表中。这些行具有相同的位置,当我运行程序时,它将继续指向最新的数据并将其放入列表中。这意味着如果我在while循环中有一个名为printL()的函数。它会打印
123/
1223/1223/
21432/21432/21432/
而不是
123/
123/1223/
123/1223/21432
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct n{
char *value;
struct n *next;
} Node;
void printList(Node *head){
Node *cur = head;
while(cur!=NULL){
printf("%s/", cur->value);
cur = cur->next;
}
printf("\n");
}
void insertIntoList(Node **head, char *data){
Node *newNode = malloc(sizeof(Node));
if (newNode == NULL){
perror("Failed to allocate a new node for the linked list");
exit(1);
}
newNode->value = data;
newNode->next = NULL;
Node *currentList = *head;
if(*head == NULL){ //if the linked list head is null, then add the target into linked list
*head = newNode;
}
else{
while(currentList->next!=NULL){
currentList = currentList->next;
}
currentList->next = newNode;
}
}
int main(int argc, char**argv){
FILE *fileStream;
size_t len = 0;
char *line = NULL;
Node *head = NULL;
int j;
for(j=1; j<argc-2;j++){
fileStream = fopen(argv[j], "r");
if(fileStream == NULL){
fprintf(stderr, "could not open");
continue;
}
insertIntoList(&head,"a"); /////////////Line 95
insertIntoList(&head,"b");
insertIntoList(&head,"c");
insertIntoList(&head,"d");
printf("here is a try\n");
printList(head);
while(getline(&line, &len, fileStream)!=EOF){ /////////////Line 101
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
printf("######print head here is##########\n");
printList(head);
printf("######print head here is##########->\n");
}
//printList(head);
}
return 0;
}
答案 0 :(得分:0)
为了保持从strtok()
返回的每个已加载字段的内容,只需在检查是否为空指针后调用strdup()
之前添加insertIntoList()
。
在您的代码中,如果您比较
line
和targetNum
的值 是相同的。事实上,strtok()
函数返回一个指针 输入字符串并保留下一个参数的指针。
替换以下代码:
char *targetNum = strtok(line, " \t\r\n");
printf("*****%s\n", targetNum);
insertIntoList(&head, targetNum);
通过那个:
char *targetNum = strtok(line, " \t\r\n");
if (targetNum != NULL) {
printf("*****%s\n", targetNum);
insertIntoList(&head, strdup(targetNum));
}
答案 1 :(得分:0)
您不会在列表节点中存储字符串的内容;存储指向用于字符串内容的缓冲区的指针。
考虑将列表节点结构更改为
typedef struct node Node;
struct node {
Node *next;
char data[];
};
其中字符串的内容存储在C99 flexible数组成员中。
您的节点构造函数就像
Node *new_node(const char *data)
{
const size_t datalen = (data) ? strlen(data) : 0;
Node *result;
result = malloc(sizeof (Node) + datalen + 1);
if (!result) {
fprintf(stderr, "Out of memory!\n");
exit(EXIT_FAILURE);
}
if (datalen > 0)
memcpy(result->data, data, datalen);
result->next = NULL;
result->data[datalen] = '\0';
return result;
}
看看函数如何为数据副本分配内存?
就个人而言,我更喜欢像
这样的东西typedef struct node Node;
struct node {
Node *next;
size_t hash;
size_t size;
char data[];
};
其中size
成员基本上是strlen(data)
(除了您还可以使用节点来保存包含空字节\0
的二进制数据),hash
是从data
计算的简单hash。如果您打算比较节点的全部内容,hash
非常有用;如果两个节点&#39;长度或散列不同,则可以肯定它们的内容不同;如果它们是相同的,那么然后你逐个字符地比较它们(memcmp(node1->data, node2->data, node1->length) == 0
如果它们是相同的)。
上面的构造函数就像(使用DJB2哈希):
Node *new_node(Node *next, const void *data, const size_t size)
{
Node *result;
result = malloc(sizeof (Node) + size + 1);
if (!result) {
fprintf(stderr, "new_node(): Out of memory (%zu bytes)\n", size);
exit(EXIT_FAILURE);
}
/* Copy and hash data using DJB2 hash (not that good, but fast) */
{
unsigned char *src = (unsigned char *)data;
unsigned char *const end = (unsigned char *)data + size;
unsigned char *dst = result->data;
size_t hash = 5381;
while (src < end) {
hash = hash * 33 + (size_t)(*src);
*(dst++) = *(src++);
}
/* Add terminator */
*dst = '\0';
}
result->next = next;
result->hash = hash;
result->size = size;
return result;
}
这些Node
也可用于例如哈希表,这使得该类型非常通用。