字符指针分段故障

时间:2012-04-17 05:39:04

标签: c arrays string pointers

好的,这就是发生了什么的要点:

我将一个字符数组(char[x])传递给一个函数,该函数的参数被定义为字符指针(char *)。一旦进入函数,我就分配另一个字符指针(这是我所拥有的结构的一部分)。一旦我将传入的参数分配给结构的字符指针,我就会出现分段错误;就这样。

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

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

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

以下是我如何利用错误:

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

与上面相同的声明,它工作正常。我确定它不是别的,通过将名称改为常量“HEY”,输入相同,一切顺利。

如果有人能够想到一个他们头脑发热的原因,我将非常感谢他们的帮助。谢谢!

以下是完整的功能:

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

以下是所涉及结构的简要概述。 open结构是指向另一个结构的指针的链接列表(称为set结构) 集合结构是名称,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);

3 个答案:

答案 0 :(得分: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",没有空终止符。

如果你的函数假定它得到一个以空字符结尾的字符串(超过可能),那么第二个变体可能会导致段错误。

答案 1 :(得分:0)

从sniplet中不确定如何声明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

答案 2 :(得分: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;
  }
}