簡體   English   中英

字符指針分割故障

[英]Char Pointer Segmentation Fault

好的,這是正在發生的事情的要點:

我正在將一個字符數組(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 /鍵在鏈接列表中查找結構
  • 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);

首先,這兩行:

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

最上面一行沒有用,會導致內存泄漏。

其次,這兩行:

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

接近但不完全相同。 第一個結果導致name指向一個4字節的數據塊,並以字符串"HEY"和結尾的空終止符(值0'\\0' )結束。 第二個結果導致name指向一個3字節的內存塊,其中的字節為"HEY" ,沒有空終止符。

如果您的函數假定它正在獲取一個以空值結尾的字符串(很有可能),則第二個變量可能會導致段錯誤。

從片段中不確定如何聲明temp- temp->name ,但是問題可能出在這里。

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

由於char的大小只有一個字節,並且取決於要存儲的內容,因此您需要一個用於完整指針的空間(4或8個字節),或者如果您希望將內容復制到分配的空間中,則需要一個char序列。

所以

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

要么

 name = (char*)malloc(sizeof(char) * 80 ); // for 80 bytes char array

因此,讓我們從頭開始。 您從文件中讀取密鑰,字符串數據對。 您可以按照閱讀順序來建立這些對的鏈接列表。 那呢

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM