【问题标题】:Debugging A Segmentation Fault in C Program调试 C 程序中的分段错误
【发布时间】:2014-01-29 16:43:21
【问题描述】:

我想要做的是创建一个 10x10 数组并只打印出对角线上的值,它目前是段错误,所以我有几个问题。 1. 使用终端 shell 在 Mac 上调试段错误的最简单方法是什么? 2. 我试图找出这个函数的段错误?我尝试在 values = malloc... 行上方添加一个简单的 printf 语句,但它甚至没有达到我想不到的程度。

int **values;

int i, j;
values = malloc(10 * sizeof(int *));
for (i = 0; i < 10; i++){
    for (j = 0; j < 10; j++){
        values[i][j] = i * j;
} 
}
    for (i = 0; i < 10; i++)
    printf("%d ", values[i][i]);
printf("\n");

【问题讨论】:

  • 使用像 GDB 这样的调试器。
  • 试试int values[10][10];,不要使用malloc;或 int (*values)[10]; 和 values = malloc(10*10*sizeof(int));` 。每次调试后还要加上fflush(stdout);printf
  • 你有 mallocd 空间来存放 10 个指针,但你从来没有让它们指向任何东西。
  • @Marian 这是错误的:malloc(10*10*sizeof(int *));。考虑到它前面的类型,使用int (*values)[10] = malloc(10*sizeof(*values)) 就足够了。
  • 在人们开始为你发帖后,你到底是在完全改变你的问题吗?

标签: c segmentation-fault


【解决方案1】:

如果您使用的是运行某些 OS X 版本的 Mac,则应该同时安装 gcc 和 gdb。如果没有,它们很容易下载和安装。我在 Linux 系统上运行,但下面的步骤和输出在 OS X 上应该类似。

为了在调试器中查看您的源代码,您必须使用-g 选项编译它:gcc -o myprog -g myprog.c。否则,您只会看到生成的机器代码。

此时,您可以正常运行程序并让它转储您将加载到 gdb 中的核心文件,或者在 gdb 中启动程序并逐行执行。

我冒昧地获取了您的代码并从中创建了一个完整的程序:

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

int main( void )
{
  int **values;

  int i, j;
  values = malloc(10 * sizeof(int *));
  for (i = 0; i < 10; i++){
      for (j = 0; j < 10; j++){
          values[i][j] = i * j;
      }
  }
  for (i = 0; i < 10; i++)
    printf("%d ", values[i][i]);
  printf("\n");

  return 0;
}

我们将在启用调试的情况下构建它:

$ gcc -o example -g -std=c99 -pedantic -Wall -Werror example.c

并在 gdb 中启动它:

$ gdb example
GNU gdb (GDB) SUSE (7.1-8.9.1)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-suse-linux".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/fbgo448/prototypes/coredump/example...done.
(gdb)

我们要做的第一件事是在main处设置一个断点;这将导致程序一进入主函数就暂停:

(gdb) break main
Breakpoint 1 at 0x4005a0: file example.c, line 9.

现在我们将启动在 gdb 环境中运行的程序;它将运行到下一个断点:

(gdb) r
Starting program: /home/fbgo448/prototypes/coredump/example

Breakpoint 1, main () at example.c:9
9         values = malloc(10 * sizeof(int *));

您可以一次执行一行,如下所示:

(gdb) n
10        for (i = 0; i < 10; i++){

您可以检查变量或任意内存位置的内容:

(gdb) p values
$1 = (int **) 0x501010
(gdb) p *values
$2 = (int *) 0x0
(gdb) x/1x 0x501010
0x501010:       0x00000000
(gdb) x/1b 0x501010
0x501010:       0x00
(gdb) x/10b 0x501010
0x501010:       0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x501018:       0x00    0x00
(gdb) x/10x 0x501010
0x501010:       0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x501018:       0x00    0x00

希望您已经看到了问题,但如果没有,我们可以“继续”程序并让它运行直到失败:

(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x00000000004005e3 in main () at example.c:12
12                values[i][j] = i * j;

您在尝试分配 values[i][j] 时遇到了段错误。我们再来看看:

(gdb) p i
$3 = 0
(gdb) p j
$4 = 0
(gdb) p values
$5 = (int **) 0x501010
(gdb) p values[i]
$6 = (int *) 0x0
(gdb) p values[i][j]
Cannot access memory at address 0x0

其他人已经指出了问题;您为指向int 的10 个指针分配了足够的空间,但您没有为这些指向to 的指针分配任何东西。您在分配过程中缺少一个步骤:

values = malloc( 10 * sizeof *values ); // sizeof *values == sizeof (int *)
if ( values )
{
  for ( i = 0; i < 10; i++ )
  {
    values[i] = malloc( 10 * sizeof *values[i] ); // sizeof *values[i] == sizeof (int)
    if ( values[i] )
    {
      for (j = 0; j < 10; j++ )
      {
         values[i][j] = i * j;
      }
    }
  }
}

gdb 是一个相当强大的调试器,虽然使用起来有些痛苦。

【讨论】:

  • 这个全面的答案仍然是我对gdb 的指南。谢谢!
  • @wizzwizz4:你真的想使用more authoritative reference。我的回答甚至还没有开始触及如何使用 gdb 的皮毛。
【解决方案2】:

您需要同时分配“列”和“行”。现在你只是分配指向整数的指针,你还需要自己分配整数。

int **values;

int i, j;
values = (int**)malloc(10 * sizeof(int *));

for(i = 0; i < 10; i++){
    values[i] = (int*)malloc(10 * sizeof(int)); //Small edit.
}

for (i = 0; i < 10; i++){
    for (j = 0; j < 10; j++){
        values[i][j] = i * j;
    } 
}
    for (i = 0; i < 10; i++)
    printf("%d ", values[i][i]);
printf("\n");

我对 Mac 了解不多,但我很确定您可以使用 GDB。使用调试选项编译程序以创建带有调试信息的可执行文件,当程序崩溃时,它将生成核心转储。使用 gdb 和 bon appetit 打开这个核心转储。

【讨论】:

    【解决方案3】:

    只要您的指针具有指向不允许的内存段的地址,就会发生分段错误。这种情况发生在未初始化时。大多数时候垃圾值会导致这种失败。

    为避免这种情况,请使用 calloc 而不是 malloc(),因为 calloc() 分配内存并初始化为零。

    您还需要为第二维分配空间。

    int **values;
    
    int i, j;
    values = (int**)calloc(10 * sizeof(int *));
    
    for(i = 0; i < 10; i++){
        values[i] = (int*)calloc(10 * sizeof(int)); //Small edit.
    }
    
    for (i = 0; i < 10; i++){
        for (j = 0; j < 10; j++){
            values[i][j] = i * j;
        } 
    }
      for (i = 0; i < 10; i++)
        printf("%d ", values[i][i]);
    printf("\n");
    

    【讨论】:

      【解决方案4】:

      更改代码将是最简单的方法。方法如下:

      int i, j;
      values = malloc(10 * sizeof(int*));
      for (i = 0; i < 10; i++)
      {
          values[i] = malloc(10 * sizeof(int));
          for (j = 0; j < 10; j++)
          {
              values[i][j] = i * j;
          }
      }
      

      完成后不要忘记free

      int i;
      for (i = 0; i < 10; i++)
      {
          free(values[i]);
      }
      free(values);
      

      【讨论】:

      • 要免费,我们所要做的就是免费(10* sizeof(int*)).. 您只需完全免费地使用 malloc 正确的内容?
      • @user1837411 在这种情况下要释放它需要 11 次调用 free()free()s 与 malloc()s 数量相同。
      猜你喜欢
      • 2021-12-23
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      • 2012-10-12
      • 2018-11-18
      • 2011-05-23
      • 1970-01-01
      • 2021-01-08
      相关资源
      最近更新 更多