我有一个函数,给定一个指向字符数组的指针 * 字符串 *(通过引用传递),char * 字符 *(按值传递)和无符号短整型 * 长度 (通过引用传递),如果 string 已经分配,则重新分配 string 一个字符的大小((length + 2) sizeof(char)),然后将 length 递增1,将最后两个字符分别设置为 character 和空终止符。如果 string 尚未分配,在初始化字符之前,它会为 string 分配两个字符的长度(2 * sizeof(char))。但是,当它设置最后一个字符(index of length)时,它会segfaults。
void appendCharacterToString(char** string, char character, unsigned short int * length) {
if (*string != NULL) {
*string = (char* ) realloc(*string, (*length + 2) * sizeof(char));
++*length;
}
else {
*string = (char* ) malloc(2 * sizeof(char));
*length = 1;
}
*string[*length - 1] = character;
*string[*length] = 0;
}
字符串
当在gdb中运行它时,我能够确定最初分配的数组,尽管硬编码为分配两个字符的内存,但只分配一个字符,奇怪的是,它已经初始化为null。
Program received signal SIGSEGV, Segmentation fault.
appendCharacterToString (string=0x7fffffffe0d8,
character=110 'n', length=0x7fffffffe0d0)
at hangmanstringutils.c:24
24 *string[*length] = 0;
(gdb)
(gdb) print string
$1 = (char **) 0x7fffffffe0d8
(gdb) print *string
$2 = 0x5555555592a0 "n"
(gdb) print *length
$3 = 1
(gdb) continue
Continuing.
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) break hangmanstringutils.c:12
Breakpoint 1 at 0x555555555612: file hangmanstringutils.c, line 14.
(gdb) run
Starting program: /home/joseph/code/hangman/hangman
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
Breakpoint 1, appendCharacterToString (
string=0x7fffffffe0d8, character=110 'n',
length=0x7fffffffe0d0) at hangmanstringutils.c:14
14 if (*string != NULL) {
(gdb) print *string
$4 = 0x0
(gdb) print *length
$5 = 0
(gdb) break 19
Breakpoint 2 at 0x55555555565a: file hangmanstringutils.c, line 19.
(gdb) continue
Continuing.
Breakpoint 2, appendCharacterToString (
string=0x7fffffffe0d8, character=110 'n',
length=0x7fffffffe0d0) at hangmanstringutils.c:19
19 *string = (char* ) malloc(2 * sizeof(char));
(gdb) print *string
$6 = 0x0
(gdb) print *length
$7 = 0
(gdb) break 21
Breakpoint 3 at 0x555555555677: file hangmanstringutils.c, line 23.
(gdb) continue
Continuing.
Breakpoint 3, appendCharacterToString (
string=0x7fffffffe0d8, character=110 'n',
length=0x7fffffffe0d0) at hangmanstringutils.c:23
23 *string[*length - 1] = character;
(gdb) print *string
$8 = 0x5555555592a0 ""
(gdb) print *length
$9 = 1
(gdb) print *string[0]
$10 = 0 '\000'
(gdb) print *string[1]
Cannot access memory at address 0x2c0
(gdb)
型
3条答案
按热度按时间e7arh2l61#
编辑(在此回答之前)
OP的问题源于没有认识到运算符
[]
的优先级高于*
。因此,
string[x]
在**解引用之前被处理。代码尝试取消引用垃圾地址并触发错误。
简单的解决方法是将
*string
放在一对()
中。例如:(*string)[x]
(The在这个函数中使用的间接法只会使读者感到困惑。)
正确的解决方法是OP重写函数,消除间接的不必要的复杂性。
继续我之前的回答……
代码太多了!我真的不想去理解代码到底出了什么问题。
void
函数需要对两个参数使用间接法。1.避免
strlen()
而追求复杂性是一个糟糕的选择。1.* 强制转换 * 从
malloc()
和realloc()
返回的void *
是不好的做法1.不阅读手册:如果
realloc()
的第一个参数是NULL
,则realloc()
的行为与malloc()
类似。sizeof(char)
可能是有意义的,如果程序可能与更大的字符类型一起使用。1.“信任”调用者没有不适当地更改
length
的值。1.未验证堆分配是否成功。
还有这个
字符串
测试结果:
型
请不要问为什么糟糕的/过于复杂的代码不能工作。
培养一种感觉,什么是正确的,清晰的,简洁的代码......什么不是......
vecaoik12#
print *string[1]
不访问*string
的索引1处的字符。它是*(string[1])
,而不是(*string)[1]
。它访问string[1]
指向的字符,string[1]
表示内存中*string
之后的字节。您希望在调试器命令中使用print (*string)[1]
。类似地,在源代码中,您希望:字符串
kkih6yb83#
你在这段代码中有很多问题。我强烈建议不要使用副作用。
字符串