如何在c中存储具有相同内存位置的值?

时间:2016-10-30 22:05:10

标签: c memory memory-management

如果我有一个包含内容的文件流

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;
}

2 个答案:

答案 0 :(得分:0)

为了保持从strtok()返回的每个已加载字段的内容,只需在检查是否为空指针后调用strdup()之前添加insertIntoList()

  

在您的代码中,如果您比较linetargetNum的值   是相同的。事实上,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也可用于例如哈希表,这使得该类型非常通用。