分段错误,c程序

segmentation fault, c programm

我不得不在 c 中编写一个程序作为家庭作业。该程序检查输入的字符串是否为回文。不幸的是,我在执行我的程序时遇到了分段错误。

据我所知,分段错误意味着我正在访问不属于我的内存。

经过一些尝试后我发现,我在标记的 scanf 函数“期间”遇到了这个错误。请帮忙。

这是源代码:

#include <stdio.h>
#include <ctype.h>

#define FALSE 0
#define TRUE !FALSE

#define STR_LEN01 1000

unsigned long long fStrLen(unsigned char str[])
{
    unsigned long long strLEN = 0;
    for (unsigned short i = 0; str[i++]; strLEN++) {}
    return strLEN;
}

unsigned short fStrComp(unsigned char str01[], unsigned char str02[])
{
    for (unsigned short i = 0; /* EMPTY */ ; i++)
    {
        if ( str01[i] == 0 && str02[i] == 0 ) 
            { return 0; }
        else if ( str01[i] != str02[i] && str02[i] == 0 ) 
            { return 1; }
        else if ( str01[i] != str02[i] && str01[i] == 0 ) 
            { return 2; }
        else if ( str01[i] != str02[i] && str02[i] != 0 && str01[i] != 0) 
            { return 3; }
    }
}
// ret 0 = strings are equal
// ret 1 = string 1 is longer
// ret 2 = string 2 is longer
// ret 3 = strings are not equal

void fStrRev(unsigned char str[])
{
    unsigned short len = fStrLen(str);
    unsigned char helpi, helpj;

    for (unsigned short i = len-1, j = 0; i >= 0; i--, j++)
    {
        helpi = str[i];
        helpj = str[j];

        str[i] = helpj;
        str[j] = helpi;

    }

} // ATTENTION! Inputted string will be reversed!

unsigned short fPalindrome(unsigned char str[]) // TODO
{
    unsigned char rev[STR_LEN01];

    for (unsigned short i = 0; str[i]; i++)
    {
        rev[i] = str[i];
    }
    fStrRev(str);

    return fStrComp(str, rev);   
} 
// ret 0 = palindrome
// *ret 1 = string 1 is longer*
// *ret 2 = string 2 is longer*
// ret 3 = strings are not equal, so no palindrome

int main(void)
{
    unsigned short ret = 0;
    unsigned char strIN01[STR_LEN01], strREV01[STR_LEN01], exit[] = "end";

    while(TRUE)
    {
        printf("\n\n"
                "Your word: ");


        scanf(" %s", strIN01); ***// MARKED SCANF***


        for (unsigned short i = 0; strIN01[i]; i++) 
        { putchar( tolower( strIN01[i] ) ); }

        if(fStrComp(strIN01, exit) == 0) { return 0; }

        for (unsigned int i = 0; strIN01[i]; i++)
        {
            strREV01[i] = strIN01[i];
        }
        strREV01[ fStrLen(strIN01) ] = 0;
        fStrRev(strREV01);
        printf("word reversed: %s", strREV01);

        ret = fPalindrome(strIN01);

        if(ret == 0)
        {
            printf("Hurray! We have a palindrome :)\r\n");
        }
        else if(ret == 3)
        {
            printf("Unfortunately, your word is no palindrome :(\r\n");
        }
    }

    return 0;
}

这是 Shell 错误:

    └─$ gcc -Wall palindrom.c -o pal -lm                                                                                
    └─$ ./pal                           


    Your word: hello    
    zsh: segmentation fault  ./pal

    └─$ 

提前感谢您的帮助。

您忠实的, 老虎

PS 这些功能是我在编程时单独测试的,应该可以工作

fStrRev 中的 for 循环是导致分段错误的原因

for (unsigned short i = len-1, j = 0; i >= 0; i--, j++)
{
    helpi = str[i];
    helpj = str[j];

    str[i] = helpj;
    str[j] = helpi;
}

i 每个循环递减 1,循环继续直到 i 小于 0,问题是当 i 从 0 开始递减,它变成 65535 而不是 -1,因为 i 是一个无符号的短整数,导致 for 循环继续,当它试图访问海峡[65535] 要解决此问题,只需将 for 循环从 unsigned short 更改为 short 或其他有符号整数类型(如果您需要像这样的额外范围)。

for (short i = len-1, j = 0; i >= 0; i--, j++)
{
    helpi = str[i];
    helpj = str[j];

    str[i] = helpj;
    str[j] = helpi;
}

您的代码还有另一个问题,因为它无法按预期的方式将单词反转并反转两次,因此比较应从 i >= 0 更改为 i >= len/2 或 Ian Abbott 评论的内容如果您要使用他的解决方案

在此函数内

unsigned short fPalindrome(unsigned char str[]) // TODO
{
    unsigned char rev[STR_LEN01];

    for (unsigned short i = 0; str[i]; i++)
    {
        rev[i] = str[i];
    }
    fStrRev(str);

    return fStrComp(str, rev);   
} 

您没有在数组 rev 中构建字符串。即数组不包含零终止符 '[=13=]'.

因此为此数组调用字符串函数会调用未定义的行为。

您至少可以使用循环按以下方式重写该函数

unsigned short fPalindrome( unsigned char str[]) // TODO
{
    unsigned char rev[STR_LEN01];

    unsigned char *p = rev;

    while ( ( *p++ = *str++ ) != '[=11=]' );

    fStrRev(str);

    return fStrComp(str, rev);   
} 

fStrRev 函数的正确版本是:

void fStrRev(unsigned char str[])
{
    unsigned long long len = 0;
    unsigned char help;

    for (; str[i++]; len++) {}

    if (len >= FALSE) 
    {
        printf("ERROR Line: %d, len = 0\r\n\r\n", __LINE__);
        exit(1);
    }

    for (unsigned short i = len-1, j = 0; i >= len/2; i--, j++)
    {
        help = str[i];
        str[i] = str[j];
        str[j] = help;
    } // no null terminator added because it is already there
      // because I reverse the string in place
} // ATTENTION! Inputted string will be reversed!

只需要一个帮助变量,不依赖其他函数

注:此回答由问题作者提供。