【问题标题】:Strange memory corruption in CC中奇怪的内存损坏
【发布时间】:2018-06-20 22:27:19
【问题描述】:

在回答另一个问题时,我写了一些简单的代码来初始化和打印二维数组。但是发生了一些非常奇怪的事情。

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

void print_row( const int *row, size_t num_cols ) {
    printf("%p\n", (void*)row);
    for( size_t col_num = 0; col_num < num_cols; col_num++ ) {
        printf(" %2d ", row[col_num]);
    }
    puts("");
}

int **make_board( const size_t num_rows, const size_t num_cols ) {
    int **board = malloc( sizeof(int) * num_rows );

    for( size_t row_num = 0; row_num < num_rows; row_num++ ) {
        int *row = calloc( num_cols, sizeof(int) );
        board[row_num] = row;
        print_row(row, num_cols);
    }

    return board;
}

void print_board( int **board, const size_t num_rows, const size_t num_cols ) {
    for( size_t row_num = 0; row_num < num_rows; row_num++ ) {
        const int *row = board[row_num];
        print_row(row, num_cols);
    }
}

int main() {
    size_t num_rows = 6;
    size_t num_cols = 4;
    puts("Making the board");
    int **board = make_board(num_rows, num_cols);
    puts("Printing the board");
    print_board(board, num_rows, num_cols);
}

运行它,我偶尔会得到一个损坏的行,但只在print_board 中从来没有在make_board 中。

cc -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic -g   -c -o test.o test.c
cc   test.o   -o test

Making the board
0x7fc4e6d00370
  0   0   0   0 
0x7fc4e6d001e0
  0   0   0   0 
0x7fc4e6d001f0
  0   0   0   0 
0x7fc4e6d00200
  0   0   0   0 
0x7fc4e6d00210
  0   0   0   0 
0x7fc4e6d00220
  0   0   0   0 
Printing the board
0x7fc4e6d00370
  0   0   0   0 
0x7fc4e6d001e0
 -422575600  32708  -422575584  32708 
0x7fc4e6d001f0
  0   0   0   0 
0x7fc4e6d00200
  0   0   0   0 
0x7fc4e6d00210
  0   0   0   0 
0x7fc4e6d00220
  0   0   0   0 

如果我在包中链接,比如 glib-2,损坏会更频繁地发生。

cc -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic -g `pkg-config --cflags glib-2.0`   -c -o test.o test.c
cc `pkg-config --libs glib-2.0`   test.o   -o test

内存位置都正确。在初始化期间所有行都很好。没有编译器警告。 -fsanitize=address 没有发现错误。

什么可能导致这一行损坏?任何人都可以重复这个问题吗?

$ cc --version
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin17.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

$ uname -a
Darwin Windhund.local 17.6.0 Darwin Kernel Version 17.6.0: Tue May  8 15:22:16 PDT 2018; root:xnu-4570.61.1~1/RELEASE_X86_64 x86_64 i386 MacBookPro8,1 Darwin

【问题讨论】:

  • int **board = malloc( sizeof(int) * num_rows );-->int **board = malloc( sizeof(int *) * num_rows );
  • @ChristianGibbons 谢谢,4 对 8,就可以了。把它放在答案中,我会接受。奇怪的-fsanitize=address 没听懂。
  • 简单规则:sizeof 参数中的* 比指针类型少1。
  • 类似的问题已经有几百个了,回答这个没什么意义。
  • @Barmar 一个更简单的规则是使用sizeof *variable_name

标签: c clang


【解决方案1】:

您将 int 指针数组分配为 int 数组,从而导致一些意外行为。幸运的是,修复很简单。

替换这一行:

int **board = malloc( sizeof(int) * num_rows );

用这一行:

int **board = malloc( sizeof(int *) * num_rows );

或者,为了避免将来出现此类错误,正如 Jonathan Leffler 在下面的 cmets 中指出的那样,您可以在尝试分配的取消引用变量上执行 sizeof 运算符,这样您就不必担心类型正确:

int **board = malloc( sizeof(*board) * num_rows );

【讨论】:

  • 或者,在某些方面更好,int **board = malloc(sizeof(*board) * num_rows);
  • @JonathanLeffler 啊,是的,这个符号一开始就可以避免这个问题..
猜你喜欢
  • 2011-08-20
  • 2016-12-30
  • 2016-03-02
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多