1

さて、ここに何が起こっているかの要点があります:

(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);

4

3 に答える 3

1

まず、これらの2行:

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

一番上の行は役に立たず、メモリ リークを引き起こします。

次に、次の 2 行:

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

近いですが同一ではありません。最初の結果は、最後に文字列とヌル ターミネータ (値または)nameを持つ 4 バイトのデータ チャンクを指します。2 番目の結果は、3 バイトのメモリ チャンクを指し、バイトがあり、ヌル ターミネータはありません。"HEY"0'\0'name"HEY"

関数が null で終わる文字列を取得していると想定している場合 (可能性が高い)、2 番目のバリアントはおそらく segfault を引き起こします。

于 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 のサイズはわずか 1 バイトであるため、格納する内容に応じて、完全なポインター (4 または 8 バイト) 用のスペースが必要になるか、コンテンツを割り当てられたスペースにコピーする場合は一連の文字が必要になります。

そう

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

または

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