分段错误,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!
只需要一个帮助变量,不依赖其他函数
注:此回答由问题作者提供。
我不得不在 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!
只需要一个帮助变量,不依赖其他函数
注:此回答由问题作者提供。