博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C字符串分析(使用GDB调试进行地址分析)
阅读量:4126 次
发布时间:2019-05-25

本文共 2396 字,大约阅读时间需要 7 分钟。

作者:lwyang?

在 C 语言中,字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

下面的声明和初始化创建了一个 “Hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello” 的字符数多一个。

char greeting[6] = {
'H', 'e', 'l', 'l', 'o', '\0'};

依据数组初始化规则,我们可以把上面的语句写成以下语句:

char greeting[] = "Hello";

以下是 C/C++ 中定义的字符串的内存表示:

在这里插入图片描述
其实,我们不需要把 null 字符放在字符串常量的末尾。C 编译器会在初始化数组时,自动把 ‘\0’ 放在字符串的末尾。


那么接下来大家看以下这个程序的输出结果:

//test.c#include
#include
int main(){
char str[] = "12345"; char tmp1[5]; char tmp2[5]; printf("str length: %d\n",strlen(str)); strncpy(tmp1, str, 5); sprintf(tmp2, "%s", str); printf("strcpy tmp1: %s\n", tmp1); printf("sprintf tmp2: %s\n", tmp2); printf("str :%s\n, str); printf("str length: %d\n",strlen(str));}
gcc -g test.c

输出结果:

在这里插入图片描述
这个程序的结果非常奇怪
第一行 str length : 5 没有问题,sizeof(str)= 6
第二行发现 tmp1:1234512345
然后最后发现str变为了空字符串

我们可以使用gdb进行调试分析为什么会出现这样的结果:

gdb ./a.out

启动GDB调试工具:

l 输出代码正常

在这里插入图片描述

start 启动程序,在main()处暂停

在这里插入图片描述

n 单步执行

在这里插入图片描述

p  &str       p  &tmp1p  &tmp2查看str, tmp1, tmp2的地址

在这里插入图片描述

我们可以发现str,tmp1,tmp2是连续的地址空间tmp1 tmp2 str

tmp1 = 0x7fffffffdec8
tmp2 = 0x7fffffffdecd
str = 0x7fffffffded2
tmp1 + 5 = tmp2
tmp2 + 5 = str

接下来打印从tmp1地址(0x7fffffffdec8)开始的16个字节,可以看看里面都是存的什么

x/16cb  0x7fffffffdec8

在这里插入图片描述

可以看到:

tmp1: '\200'   '\F'   'U'   'U'   'U'tmp2:  'U'   '\000'   '\000'   '\300'   '\337'str:  '1'   '2'   '3'   '4'   '5'

由于tmp1tmp2没有进行初始化,因此里面的内容不能确定

但可以看到从str开始的地址存放的正是“12345”

n然后继续单步执行完strncpy(tmp1, str, 5);

x/16cb  0x7fffffffdec8

在这里插入图片描述

到这里我们可以看到strncpy(tmp1, str, 5);已经起作用了,它将tmp1里面的内容替换为了“12345”, 而tmp2str里的内容是不变的

tmp1: '1'   '2'   '3'   '4'   '5'tmp2:  'U'   '\000'   '\000'   '\300'   '\337'str:  '1'   '2'   '3'   '4'   '5'

strncpy 函数是没有在字符串末尾自动添加’\0’的

若在这里进行tmp1,tmp2,str的输出,则结果为:

在这里插入图片描述

n然后继续单步执行完sprintf(tmp2, "%s", str);

x/16cb  0x7fffffffdec8

在这里插入图片描述

到这里我们可以看到sprintf(tmp2, "%s", str);已经起作用了,它将tmp2里面的内容替换为了“12345”, 而且发现在tmp2末尾自动添加了'\0', 即str地址开始的字符(0x7fffffffded2)变为了'\0',这里就不难理解为什么str最后的length变为了0。

tmp1: '1'   '2'   '3'   '4'   '5'tmp2:  '1'   '2'   '3'   '4'   '5'str:  '\000'   '2'   '3'   '4'   '5'

sprintf 函数会自动在字符串末尾添加’\0’

n然后继续单步执行完程序

在这里插入图片描述

根据上面的分析结果可以看到下面最后tmp1tmp2str里面的存的内容:

tmp1: '1'   '2'   '3'   '4'   '5'tmp2:  '1'   '2'   '3'   '4'   '5'str:  '\000'   '2'   '3'   '4'   '5'

tmp1的输出为1234512345

因为tmp1,tmp2,str的地址空间连续,只有遇到’\0’结束符时程序才会认为到了字符串末尾,因此会一直输出直至到str的第一个字符结束
同理tmp2的输出为12345

str的第一个字符已经变成了结束符'\0',因此str输出为空,str length为0


以上通过查看内存地址分析了程序为什么会出现这么奇怪的执行结果,所以在进行字符串操作时一定要注意结束符,不然会出现意想不到的问题,如有不正确的地方还请指出来一起交流!?

转载地址:http://juhpi.baihongyu.com/

你可能感兴趣的文章
2019年哪些外快收入可达到2万以上?
查看>>
【JavaScript 教程】标准库—Date 对象
查看>>
前阿里手淘前端负责人@winter:前端人如何保持竞争力?
查看>>
【JavaScript 教程】面向对象编程——实例对象与 new 命令
查看>>
我在网易做了6年前端,想给求职者4条建议
查看>>
SQL1015N The database is in an inconsistent state. SQLSTATE=55025
查看>>
RQP-DEF-0177
查看>>
Linux查看mac地址
查看>>
Linux修改ip
查看>>
MySQL字段类型的选择与MySQL的查询效率
查看>>
Java的Properties配置文件用法【续】
查看>>
JAVA操作properties文件的代码实例
查看>>
IPS开发手记【一】
查看>>
Java通用字符处理类
查看>>
文件上传时生成“日期+随机数”式文件名前缀的Java代码
查看>>
Java代码检查工具Checkstyle常见输出结果
查看>>
北京十大情人分手圣地
查看>>
Android自动关机代码
查看>>
Android中启动其他Activity并返回结果
查看>>
2009年33所高校被暂停或被限制招生
查看>>