关于C#:Char指针分割错误

Char Pointer Segmentation Fault

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

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

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

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

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

这是我错误地利用它的方式:

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

与上述相同的语句,它可以正常工作。通过将名称更改为恒定的" HEY"(具有相同的输入),一切顺利进行,我确保没有其他问题。

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

这是完整的功能:

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

这是所涉及结构的简要说明。
开放结构是指向另一个结构(称为集合结构)的指针的链接列表。
集合结构是名称,sid和项结构的链接列表
项目结构是数据和键的链接列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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);


首先,这两行:

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

最上面一行没有用,会导致内存泄漏。

其次,这两行:

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

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

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


因此,让我们从头开始。您从文件中读取密钥,字符串数据对。您可以按照阅读顺序来建立这些对的链接列表。那呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
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
"
, 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
"
, node->key, node->value);
  } else {
    printf("not found!
"
);
  }
  if (is_in_list(head,"abcd3")) {
    printf("found key in list but now I don't know the value associated with this key.
"
);
  } else {
    printf("not found!
"
);
  }
  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;
  }
}


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

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

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

所以

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

要么

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