老规矩,先放代码。
//回文数
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main(void)
{
char* input = NULL;
int size = 100;
input = (char*)malloc(size*sizeof(char));//动态分配内存,最后别忘了free;
printf("Input string:");
fgets(input,size,stdin);
input[strcspn(input,"\n")] = '\0';//这里注意,fgets会读入换行符,这里需要将换行符去除。
int len = strlen(input);
int isplalindrome = 1;//使用0和1判断
for(int i = 0;i < len/2;i ++)
{
if (*(input + i) != *(input + len - 1 -i))//将指针当作数组用。input + i == input[0 + i]
{
isplalindrome = 0;//证明不是回文数
break;
}
}
if (isplalindrome == 1)
{
printf("Yes");
}
else printf("No");
free(input);
return 0;
}
- 关于换行符的问题
在敲代码的过程中,笔者还注意到了一个有意思的小细节。
fgets(input,size,stdin);
由于习惯,笔者采用了更为安全的输入方式fgets。相比于已经废弃的gets,这种输入方式可以有效地防止溢出,当我们的输入长度超过size时,fgets会自动截取size内的字符而防止报错(类似于scanf函数中的%100s)。
然而在运行时,笔者却发现使用gets函数能正确地判断是否为回文数,但是fgets函数却总是输出“NO”。明明fgets函数更安全,为什么使用它就会报错呢?
我们通过实践,先了解strlen函数、gets函数和fgets函数的性质。
#include "stdio.h"
#include "string.h"
int main(void)
{
char str1[10] = "student";
char str2[10],str3[10];
gets(str2);
fgets(str3,10,stdin);
printf("length of str1 = %d\n",strlen(str1));
printf("length of str2 = %d\n",strlen(str2));
printf("length of str3 = %d\n",strlen(str3));
return 0;
}
在段代码中,我们使用初始化、gets函数输入、fgets函数输入三种方式,分别定义了字符串"student",随后用strlen函数计算并输出他们的长度。
那么结果是什么呢?
student
student
length of str1 = 7
length of str2 = 7
length of str3 = 8
进程已结束,退出代码为 0
我们看到,同样是输入了相同的字符串,str3的长度比str2多了1.这是为什么呢?
我们再对代码做一点小小的修改:
#include "stdio.h"
#include "string.h"
int main(void)
{
char str1[10] = "student";
char str2[10],str3[10];
gets(str2);
fgets(str3,10,stdin);
str3[strcspn(str3,"\n")] = '\0';//使用strcspn函数清除可能存在的换行符
printf("length of str1 = %d\n",strlen(str1));
printf("length of str2 = %d\n",strlen(str2));
printf("length of str3 = %d\n",strlen(str3));
return 0;
}
student
student
length of str1 = 7
length of str2 = 7
length of str3 = 7
进程已结束,退出代码为 0
此时长度一样了!
由此我们可以得出三个结论:
- gets函数输入不包括换行符;
- fgets函数输入包括换行符;
- strlen函数计算长度时,会包含换行符的长度,但不包含终止符'\0'的长度.
因此在初始代码中,笔者使用fgets后,并没有通过strcspn()搜索存在的换行符并将其替换成终止符'\0',导致字符串长度计算错误(总是多1)(比如student的长度本来是7,因为多了换行符而计算成8),除非在前后都输入换行符,否则回文数的计算会一直出现错误。
注意到此点后,笔者又上手实践了一下,证明scanf函数也不会读入换行符。但是scanf函数在读取数据时会忽略空白字符,包括空格、制表符和换行符。这意味着,如果我们在输入数据之间或之后按下了回车键,scanf函数会自动忽略这些换行符,并继续等待下一个非空白字符的输入。
由此,我们在使用fgets函数时,不要忘记清除可能存在的换行符。
over.