1

好的,这是正在发生的事情的要点:

我将一个字符数组传递给(char[x])一个函数,其参数被定义为一个字符指针(char *)。一旦在函数内部,我分配了另一个字符指针(这是我拥有的结构的一部分)。将传入参数分配给结构的字符指针后,我会立即遇到分段错误;像这样。

temp->name = (char*)malloc(sizeof(char));
temp->name = name;

这就是我之前使用该功能的方式:

char *name = "HEY";
Function(name);

以下是我在错误中使用它的方式:

char name[3] = "HEY";
Function(name);

与上面相同的语句,它工作正常。通过将名称更改为常量“嘿”,使用相同的输入,我确保它不是其他任何东西,一切都很顺利。

如果有人能想到一个原因,我将非常感谢您的帮助。谢谢!

这是完整的功能:

  • openList 是指向结构链表开头的指针
  • tempOpen 是一个临时指针,我们可以利用它来搜索列表,而不改变 openList 的位置
  • findOpenSetSID/findItem -> 通过 SID/key 在链表中查找结构
  • answerOpen/answerItem -> 1 == 第一个节点,2 == 任何其他节点,0 = 未找到

以下是所涉及结构的简要摘要。 开放结构是指向另一个结构的指针的链表(称为集合结构) 集合结构是名称、sid 和项结构的链表 项结构是数据和键的链表

Error_t WRITE(Sid_t sid, char *key, char *data){

 Open_p_t tempOpen = openList;      //setting a pointer to a struct 
 int answerOpen = findOpenSetSID(sid, &tempOpen);   
 if(answerOpen > 0){
    Set_p_t targetNode;             
    if(answerOpen == 1){
        targetNode = tempOpen->file;        
    }
    else{
        targetNode= tempOpen->next->file;   
    }
    Item_p_t tempItem = targetNode->items;      
    int answerItem = findItem(key, &tempItem);  
    Item_p_t targetItem;                
    targetItem = (Item_p_t)malloc(sizeof(Item_t));
    if(answerItem > 0){
        if(answerItem == 1){
            targetItem = targetNode->items;
        }
        else{
            targetItem = targetNode->items->next;
        }
        targetItem->data = data;        
    }
    else{
        **targetItem->data = data;**      <<<The problem line.
                                                      basically I am just adding   
                                                      items to my sets. But this line 
                                                      freaks out when the input changes 
                                                      from char* to char[]
        targetItem->key = key;

        targetItem->next = targetNode->items;
        targetNode->items = targetItem;
    }
    return 0;
}
return 1;
}

这是输入段:

char key[32], data[64]; // reads in data using fscanf(fd, "%s %s", key data) then calls WRITE(setId, key, data);

4

3 回答 3

1

首先,这两行:

temp->name = (char*)malloc(sizeof(char));
temp->name = name;

顶行是无用的,会导致内存泄漏。

其次,这两行:

char *name = "HEY";
char name[3] = "HEY";

接近但不相同。第一个结果name指向一个 4 字节的数据块,其中包含字符串"HEY"和结尾的空终止符(值0'\0')。第二个结果name指向一个 3 字节的内存块,其中包含字节"HEY"且没有空终止符。

如果您的函数假定它正在获取一个以 null 结尾的字符串(很可能),那么第二个变体可能会导致段错误。

于 2012-04-17T05:48:31.667 回答
0

所以让我们从头开始。您从文件中读取字符串的键、数据对。您按照阅读它们的顺序构建这些对的链接列表。然后呢?

/*
compile with:
gcc -std=c89 -pedantic -Wall -O2 -o so_10185705 so_10185705.c
test with:
valgrind ./so_10185705
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

struct node_t {
  char key[32];
  char value[64];
  struct node_t *next;
};

static void print_list(const struct node_t *curr)
{
  while (curr) {
    printf("%s, %s\n", curr->key, curr->value);
    curr = curr->next;
  }
}

static void free_list(struct node_t **currp)
{
  struct node_t *curr = *currp;
  *currp = NULL; /* don't leave dangling pointers */
  while (curr) {
    struct node_t *next = curr->next;
    curr->next = NULL;
    free((void *)curr);
    curr = next;
  }
}

/* O(n) but useful */
static const struct node_t *
find_in_list(const struct node_t *curr, const char *key)
{
  while (curr) {
    if (!strncmp(curr->key, key, sizeof(curr->key)))
      return curr;
    curr = curr->next;
  }
  return NULL;
}

/* Same as find_in_list but less useful */
static int is_in_list(const struct node_t *curr, const char *key)
{
  while (curr) {
    if (!strncmp(curr->key, key, sizeof(curr->key)))
      return 1;
    curr = curr->next;
  }
  return 0;
}

int main()
{
  struct node_t *head = NULL;
  FILE *f = fopen("foo", "r");
  if (!f) exit(1);
  while (!feof(f)) {
    struct node_t *new_node = malloc(sizeof(struct node_t));
    fscanf(f, "%s %s", new_node->key, new_node->value);
    new_node->next = head;
    head = new_node;
  }
  fclose(f);
  print_list(head);
  const struct node_t *node = find_in_list(head, "abcd2");
  if (node) {
    printf("found! key = %s, value = %s\n", node->key, node->value);
  } else {
    printf("not found!\n");
  }
  if (is_in_list(head, "abcd3")) {
    printf("found key in list but now I don't know the value associated with this key.\n");
  } else {
    printf("not found!\n");
  }
  free_list(&head);
  return 0;
}

/* explanation of bugs in OP's code */

struct node_t_2 {
  char *key;
  char *value;
  struct node_t_2 *next;
};

void build_list(FILE *f, struct node_t_2 *curr)
{
  while (!feof(f)) {
    /*
    These variable are allocated on the stack.
    Their lifetime is limited to the current scope.
    At the closing curly brace of the block in which they are declared,
    they die, the information in them is lost and pointer to them become
    invalid garbage.
    */
    key char[32];
    value char[64];
    /*
    Of course, you can only read keys up to 31 bytes long and values up to 63 bytes long.
    Because you need an extra byte for the string's NUL terminator.
    fscanf puts that NUL terminator for you.
    If it didn't, you would not be able to use the data:
     you would not know the lenth of the string.
    If you need 32-byte long keys, declare the variable key to be 33 bytes long.
    */
    fscanf(f, "%s %s", key, value);
    /* You can use key and value here */
    struct node_t_2 bad_new_node;
    /*
    You cannot add bad_new_node to the list, because as soon as you
    reach '}' it will die.
    You need a place for the node that will not disappear
     (be reused on the next iteration of the loop).
    So it must be on the heap.
    How many bytes do you need for the node? Enough to hold the three pointers:
     12 bytes on 32bit, 24 bytes on 64bit.
    The compiler knows how many bytes a struct needs.
    */
    struct node_t_2 *new_node = malloc(sizeof(struct node_t_2));
    /*
    You can add new_node to the list, because it is on the heap and will
     exist until either passed to free() or the process (program) exits.
    */
    new_node->key = key;
    new_node->value = value;
    /*
    That was a bug, because we stored pointers to garbage.
    Now new_node has a pointer to a place that will cease to exist
    as soon as we reach '}'.
    */
    new_node->key = strdup(key);
    new_node->value = strdup(value);
    /*
    strdup is a standard function that can be implemented like this:
    char * strdup(const char *s)
    {
      int len = strlen(s)
      char *p = malloc(len);
      memcpy(p, s, len);
      return p;
    }
    Now new_node has pointers to memory on the heap that will continue to
    exist until passed to free or the process terminates.
    */
    new_node->next = curr;
    curr = new_node;
    /*
    At the next line, memory for key and value is disappears and
     is re-used if we re-enter the loop.
    */
  }
}

/*
If your list nodes have pointers instead of arrays, you need to free
the strings pointed to by those pointers manually, becuause freeing
the list node wont free stuff it points to.
*/
free_list(struct node_t_2 **currp)
{
  struct node_t_2 *curr = *currp;
  *currp = NULL;
  while (curr) {
    struct node_t_2 *next = curr->next;
    free((void *)curr->key);
    curr->key = NULL;
    free((void *)curr->value);
    curr->value = NULL;
    curr->next = NULL;
    free((void *)curr);
    curr = next;
  }
}
于 2012-04-17T06:30:54.407 回答
0

从片段中不确定如何temp->name声明,但问题可能就在这里;

 name = (char*)malloc(sizeof(char));

由于 char 的大小只有一个字节,并且根据您要存储的内容,您需要一个完整指针(4 或 8 个字节)的空间,或者如果您希望将内容复制到分配的空间中,则需要一个字符序列;

所以

 name = (char*)malloc(sizeof(char *));

或者

 name = (char*)malloc(sizeof(char) * 80 ); // for 80 bytes char array
于 2012-04-17T06:05:54.413 回答