Malloc 未分配足够的内存,尽管已硬编码为恰好分配两个字符

问题描述 投票:0回答:1

我有一个函数,给定一个指向 char 数组string(通过引用传递)、一个 char character(通过值传递)和一个无符号短整型length(通过引用传递)的指针,假设到,如果 string 已被分配,则重新分配 string 的大小长一个字符 ((length + 2) * sizeof(char)),然后将 length 加 1,将最后两个字符设置为相等分别为字符和空终止符。如果尚未分配 string,则会在初始化字符之前分配长度为两个字符 (2 * sizeof(char)) 的 string。但是,当它设置最后一个字符(length的索引)时,它会出现段错误。

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)
c segmentation-fault heap-memory pass-by-reference c-strings
1个回答
0
投票

代码太多了!我真的不想尝试了解该代码出了什么问题。

  1. void
    函数需要对两个参数使用间接寻址。
  2. 为了复杂性而避免
    strlen()
    是一个糟糕的选择。
  3. 铸造
    void *
    malloc()
    返回
    realloc()
    是不好的做法
  4. 不阅读手册:如果第一个参数是
    realloc()
    ,则
    malloc()
    的作用类似于
    NULL
  5. 如果程序可用于更大的字符类型,
  6. sizeof(char)
    可能有意义。
  7. “相信”调用者没有不当更改
    length
    的值。
  8. 未验证堆分配是否成功。

然后,就是这个:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *appendCharacterToString( char *str, char ch ) {
    int len = str == NULL ? 0 : strlen( str );
    char *tmp = realloc( str, len + 2 );
    if( !tmp ) {
        perror( "allocation failed" );
        exit( EXIT_FAILURE );
    }
    str = tmp;

    str[ len++ ] = ch;
    str[ len   ] = 0;

    return str;
}

int main( void ) {
    char *str = NULL;

    str = appendCharacterToString( str, 'f' );
    str = appendCharacterToString( str, 'o' );
    str = appendCharacterToString( str, 'o' );
    puts( str );
    str = appendCharacterToString( str, 'b' );
    str = appendCharacterToString( str, 'a' );
    str = appendCharacterToString( str, 'r' );
    puts( str );

    free( str );

    return 0;
}

结果:

foo
foobar
© www.soinside.com 2019 - 2024. All rights reserved.