在c语言题库中看到一题:
给定程序 中函数 fun 的功能是:先将在字符串 s 中的字符按正序存放 到 t 串中,然后把 s 中的字符按逆序连接到 t 串后面。 例如:当 s 中的字符串为:“ABCDE”时,则 t 中的字符串应为:“ABCDEEDCBA”。
第一次写的代码:
#include<stdio.h>
void fun(char *s,char *t)
{
int i = 0;
int len = 0;
len = sizeof(s);
for(i = 0; i < len;i++)
{
t[i] = s[i];
}
for(i = 0; i < len; i++)
{
t[len + i] = s[len - i - 1];
}
t[2 * len] = '\0';
}
int main(void)
{
char *a = "asdf";
char *b = "qwer";
fun(a,b);
printf("%s\n",b);
return 0;
}
进入gdb调试
开始以为是循环出现了问题,于是断点在第9行,run后就直接出现
突然回想起来,字符串是保存在常量区的,只可以读不可以写
于是回到原程序,修改变第二版:
#include<stdio.h>
void fun(char *s,char *t)
{
int i = 0;
int len = 0;
len = sizeof(s);
for(i = 0; i < len;i++)
{
t[i] = s[i];
}
for(i = 0; i < len; i++)
{
t[len + i] = s[len - i - 1];
}
t[2 * len] = '\0';
}
int main(void)
{
char a[10] = "asdf";
char b[10] = "qwer";
fun(a,b);
printf("%s\n",b);
return 0;
}
将字符串保存在数组里面,数组保存在栈区里(普通数组在栈区,由malloc分配空间的数组放在堆区),是可读可写的,于是修改后运行:
再次运行还是出错,有输出为“asdf”,但是目标输出是“asdffdsa”,而且出现错误,说stack smashing detected(检测到栈区被粉碎)
于是用gdb调试一下,同样是把断点放在第九行,run后:
发现,字符创存储的地址变成栈区的空间,说明字符串存储地方应该没问题,于是无数次next后:
发现第一个for循环走了8遍…本来按照传进去的字符串(“asdf”)长度应该是4,所以for循环应该走4遍才对,现在走了8遍说明,sizeof(s)得到的不是字符串长度,而是s这个字符指针的长度,走完第一个循环后 t = “asdf0000” ,所以在进入第二个for循环(倒序相接)时,字符串 t 还是第一遍循环的值,并且值已经变成“asdf 0000 0000 fdsa”,此时整个字符串的长度已经远远超过分配的内存空间了,所以栈被粉碎了
于是继续修改,存储字符串的数组由10扩增到32:
#include<stdio.h>
void fun(char *s,char *t)
{
int i = 0;
int len = 0;
len = sizeof(s);
for(i = 0; i < len;i++)
{
t[i] = s[i];
}
for(i = 0; i < len; i++)
{
t[len + i] = s[len - i - 1];
}
t[2 * len] = '\0';
}
int main(void)
{
char a[32] = "asdf";
char b[32] = "qwer";
fun(a,b);
printf("%s\n",b);
return 0;
}
再运行程序:
虽然有输出,但是没有达到题目的要求,题目要求的是输出后变成“asdffdsa”
再次使用gdb看看:
依旧是各自循环了8次
此时输出的值是“asdf”,是因为printf遇到\0就清除缓冲区,直接输出了,所以没有打印后面的字符串,所以问题是出现在sizeof这里,需要的是字符串长度,于是使用strlen:
#include<stdio.h>
#include<string.h>
void fun(char *s,char *t)
{
int i = 0;
int len = 0;
len = strlen(s);
for(i = 0; i < len;i++)
{
t[i] = s[i];
}
for(i = 0; i < len; i++)
{
t[len + i] = s[len - i - 1];
}
t[2 * len] = '\0';
}
int main(void)
{
char a[32] = "asdf";
char b[32] = "qwer";
fun(a,b);
printf("%s\n",b);
return 0;
}
运行程序:
实现了题目要求的效果
需要注意的点:
1、字符串的存储地方
2、sizeof和strlen的区别
3、printf如何打印输出