【问题标题】:Program terminated with signal SIGSEGV, Segmentation fault程序以信号 SIGSEGV 终止,分段错误
【发布时间】:2020-08-08 13:38:34
【问题描述】:

我有一个代码 sn-p https://leetcode.com/problems/letter-combinations-of-a-phone-number/discuss/397542/C-solution

我是在网上提交的,测试通过了。然而,当我想在本地机器上进行测试时,我遇到了一个问题“程序以信号 SIGSEGV 终止,分段错误。”当它到达下一行断点 - return result。

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

void catRes(char **result, char **phone, char *digits, char *tmp, int nowIndex, 
             int *resLen) {
    
    if (nowIndex == strlen(digits)) {
        tmp[nowIndex] = 0;
        result[(*resLen)] = (char *)malloc(strlen(tmp) + 1);
        strcpy(result[(*resLen)], tmp);
        (*resLen)++;
        return;
        
    }
    char *phoneData = phone[digits[nowIndex] - '0' - 2];
    for (int i = 0; i < strlen(phoneData); i++) {
        tmp[nowIndex] = phoneData[i];
        catRes(result, phone, digits, tmp, nowIndex + 1, resLen);
    }
}

char ** letterCombinations(char * digits, int* returnSize){
    char *phone[8] = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    char **result = (char **)malloc(sizeof(char *) * 40);
    char tmp[strlen(digits) + 1];
    int resLen = 0;
    if (strlen(digits) == 0) {
        *returnSize = resLen;
        return result;
    }
    catRes(result, phone, digits, tmp, 0, &resLen);
    *returnSize = resLen;// set breakpoint here
    return result;
}


int main(){
    char s[] = {'2', '3'};
    char * digits = s;
    int * returnSize = NULL;
    char ** outcome = letterCombinations(digits, returnSize);
    ...
    return 0;

我在return result 之前的那行检查了result 的值,看起来还可以。我需要一些帮助来告诉我问题出在哪里。

【问题讨论】:

  • *returnSize = resLen; 取消引用空指针并调用 未定义的行为
  • strlen(digits) - digits 不是以 null 结尾的字节字符串,因此这也会调用 UB
  • 尝试通过Valgrind运行它
  • @cajomar 是的,它显示了一个非初始化值的访问的 lonnnng 列表,然后最终写入 0

标签: c pointers


【解决方案1】:

“程序以信号 SIGSEGV 终止,分段错误。”当它到达下一行断点时 - 返回结果。

这是因为 main 调用 letterCombinations 为 returnSize 为 NULL 所以在:

*returnSize = resLen;// set breakpoint here

你写在地址 0。


无论如何,在您有很多未定义的行为访问未初始化的值之前。例如,在 main 中,数组 s 仅包含字符 '2' 和 '3' 并且不以空字符终止,因此 strlen(digits) 具有未定义的行为读取在 s 之后,只需执行 char s[] = "23"; 即可避免这种情况。

在valgrind下执行你的程序的结果:

pi@raspberrypi:/tmp $ valgrind ./a.out
==6789== Memcheck, a memory error detector
==6789== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6789== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==6789== Command: ./a.out
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x4866210: ??? (in /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x48662D4: ??? (in /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x106B8: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x10498: catRes (c.c:8)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x10570: catRes (c.c:18)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x10498: catRes (c.c:8)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x10570: catRes (c.c:18)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x10498: catRes (c.c:8)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x10540: catRes (c.c:16)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Invalid read of size 4
==6789==    at 0x10540: catRes (c.c:16)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789==  Address 0xbd9670d0 is on thread 1's stack
==6789==  24 bytes below stack pointer
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x10570: catRes (c.c:18)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x10498: catRes (c.c:8)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x104AC: catRes (c.c:9)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x48661D8: ??? (in /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x48661DC: ??? (in /usr/lib/arm-linux-gnueabihf/libarmmem-v7l.so)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x484762C: malloc (vg_replace_malloc.c:309)
==6789==    by 0x104DB: catRes (c.c:10)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x484BA2C: strcpy (vg_replace_strmem.c:513)
==6789==    by 0x10507: catRes (c.c:11)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Use of uninitialised value of size 4
==6789==    at 0x484BA48: strcpy (vg_replace_strmem.c:513)
==6789==    by 0x10507: catRes (c.c:11)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x484BA80: is_overlap (vg_replace_strmem.c:131)
==6789==    by 0x484BA80: strcpy (vg_replace_strmem.c:513)
==6789==    by 0x10507: catRes (c.c:11)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x484BA88: is_overlap (vg_replace_strmem.c:140)
==6789==    by 0x484BA88: is_overlap (vg_replace_strmem.c:127)
==6789==    by 0x484BA88: strcpy (vg_replace_strmem.c:513)
==6789==    by 0x10507: catRes (c.c:11)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x484BA8C: is_overlap (vg_replace_strmem.c:143)
==6789==    by 0x484BA8C: is_overlap (vg_replace_strmem.c:127)
==6789==    by 0x484BA8C: strcpy (vg_replace_strmem.c:513)
==6789==    by 0x10507: catRes (c.c:11)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Conditional jump or move depends on uninitialised value(s)
==6789==    at 0x484BAA8: strcpy (vg_replace_strmem.c:513)
==6789==    by 0x10507: catRes (c.c:11)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x1059B: catRes (c.c:19)
==6789==    by 0x106D3: letterCombinations (c.c:32)
==6789==    by 0x1072B: main (c.c:42)
==6789== 
==6789== Invalid write of size 4
==6789==    at 0x106DC: letterCombinations (c.c:33)
==6789==    by 0x1072B: main (c.c:42)
==6789==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==6789== 
==6789== 
==6789== Process terminating with default action of signal 11 (SIGSEGV)
==6789==  Access not within mapped region at address 0x0
==6789==    at 0x106DC: letterCombinations (c.c:33)
==6789==    by 0x1072B: main (c.c:42)
==6789==  If you believe this happened as a result of a stack
==6789==  overflow in your program's main thread (unlikely but
==6789==  possible), you can try to increase the size of the
==6789==  main thread stack using the --main-stacksize= flag.
==6789==  The main thread stack size used in this run was 8388608.
==6789== 
==6789== HEAP SUMMARY:
==6789==     in use at exit: 304 bytes in 37 blocks
==6789==   total heap usage: 37 allocs, 0 frees, 304 bytes allocated
==6789== 
==6789== LEAK SUMMARY:
==6789==    definitely lost: 0 bytes in 0 blocks
==6789==    indirectly lost: 0 bytes in 0 blocks
==6789==      possibly lost: 0 bytes in 0 blocks
==6789==    still reachable: 304 bytes in 37 blocks
==6789==         suppressed: 0 bytes in 0 blocks
==6789== Rerun with --leak-check=full to see details of leaked memory
==6789== 
==6789== Use --track-origins=yes to see where uninitialised values come from
==6789== For lists of detected and suppressed errors, rerun with: -s
==6789== ERROR SUMMARY: 649 errors from 23 contexts (suppressed: 0 from 0)
Erreur de segmentation
pi@raspberrypi:/tmp $ 

【讨论】:

    【解决方案2】:

    我在 main 函数的末尾添加了缺少的 } 并开始摆弄你的代码一段时间。在线上

        char ** outcome = letterCombinations(digits, returnSize);
    

    在您的主函数中,您将returnSize 作为NULL 传递。现在,在您返回 letterCombinations 函数之前不久,您尝试取消引用 NULL,这就是导致 SEGFAULT 的原因。

    现在您似乎正试图将一个值从您的 letterCombinations 函数内部传播到外部。可以通过将指向有效变量的指针传递给函数来做到这一点,如下所示:

    int main(){
        char s[] = {'2', '3'};
        char * digits = s;
        int returnSize;
        char ** outcome = letterCombinations(digits, &returnSize);
        return 0;
    }
    

    关于为什么它通过了在线测试,我无法像你的主要问题那样快速回答这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多