由strcat函数引起的C语言中数组和指针问题的思考

问题一

首先,来看一下下面这段代码:数组

#include <stdio.h>
#include <string.h>
int main() {
    char *str = "media";
    char *tmp = "aaa";
    printf("str: %s\n",str);
    strcat(str,tmp);
    printf("str: %s\n",str);
    return 0;
}

代码打眼儿一看,功能很明显:把str指针指向的字符串和tmp指针指向的字符串链接起来再赋给str指向的字符串。咱们把这个程序运行一下,以下图:

报出了段错误,使用cgdb调试一下,发现问题是出在strcat函数处:

感受很奇怪,就去查找了strcat函数的一些示例,发现几乎全部的strcat的示例都是链接的两个数组类型字符串或者一个数组类型一个指针类型(指针类型指向的字符串必定是接在数组字符串以后)。本身手动测试了一下,把*str改成了str[20],发现程序成功运行:

后通过一系列的文档查阅,得知定义为指针所指向的字符串是常量字符串,只能读取不能写入。运行过程当中,指针变量p所指向的内存是分配在堆中的,且只分配了足够其指向的内容的内存。将q链接到p后,天然p是没有其余空间给q了,因此发生了段错误。要链接这样的字符串,得另外开辟一个空间存放链接起来的字符串。若是非要将两个变量定义为指针类型,能够把程序修改成如下形式:函数

#include <stdio.h>
#include <string.h>
int main() {
    char *str = "media";
    char *tmp = "aaa";
    char *res = (char *)malloc(strlen(str)+strlen(tmp)+1);
    printf("str: %s\n",str);
    strcat(strcpy(res,str),tmp);
    printf("str: %s\n",res);
    return 0;
}

获得的结果正确:
测试

问题二

这学期上了一门课,须要在Linux C中完成一个项目。其中有一个功能模块是在指定文件夹目录下递归查找当前目录下的全部文件,并将全部的文件的路径存入一个数组中。其实递归查询当前文件目录下的全部文件这个功能并不难,网上也有不少实现方法。我所遇到的问题又出在了数组和指针的问题上(指针涉及的对内存的操做真的是C的最大难点。。),下面是问题具体描述:
我所要实现的功能是,在main的参数中指定了所要扫描的文件夹,在指定文件夹下扫描全部的文件,并把所扫描到的全部文件的路径存入一个数组中。我使用了dirent.h头文件中定义的结构体,当d_type == 8是文件,d_type == 4时是文件夹。等于4时便递归调用函数实现扫描文件夹下的全部文件,发现一个,printf一个。而后定义了一个全局的char数组指针path来指向所扫描到的文件路径,在main函数下输出path来验证路径是否正确的存入了数组。主要代码以下:

而后我所要扫描的文件夹file下有三个txt文件,分别是1.txt、2.txt、3.txt:

在运行程序的时候,出现了问题:在执行readfilelist函数的时候,能够成功的发现并输出file文件夹下的三个txt文件,但是path中所存放所找到的文件路径彷佛并不正确,数组中全部的值都相同,且都是最后一个所找到的文件的路径,以下图所示(path array has following data下面输出的路径是path数组指针中的数据):

很奇怪,在readfilelist中printf一下每一次循环path中的值试试看吧,发现每一次循环输出的path中的值是正确的(以下图#后的输出结果)????????这就至关于,逐步输出path中的值是正确的,在main中从新for循环遍历一下结果就变了,path仍是一个全局变量不存在生存期的问题。并且逐步输出的时候数组下标count都是及时++的,若是是递归返回时的问题,不可能下标已是3了程序还能将数组退到0、一、2位置更改数组中的值吧。这也太奇怪了。。。。

这个结果只能有一种解释:在逐步将文件路径存入数组相应的位置时,数组全部的位置的值同时都被改变了。不过我仍是不能理解为何会发生这样的问题,立马打开cgdb。。
display一下path和局部变量ingpath(ingpath是普通字符数组类型,做用是当文件类型是文件时,将文件路径链接完整,再统一赋值给path),看看他俩的值和地址究竟是怎么变化的。
第一次扫描到3.txt文件,将值存入path中,地址后四位为d5f0:

继续执行,又找到了1.txt文件,在操做数组ingpath时出现了问题:尚未执行到给path赋值,只是在对ingpath进行修改操做时,path中的内容也发生了改变:

继续执行观察到给path赋值,发现确实和以前的猜测同样,逐步将文件路径存入数组相应的位置时,数组全部的位置的值同时都被改变了:

而且,全部通过ingpath所给path赋的值的内存地址都是相同的,都是d5f0。至此,破案了:在将数组指针path的地址指向数组变量ingpath时,path就已经绑定ingpath的地址了(和C++11中的引用&用法有些相似),数组变量的内存地址不会发生改变,并且全部对于ingpath的操做也会相应的对path进行操做。path数组指针的每一位存入数据的内存地址都相同,天然所对应的数据就相同,进而path中全部的值都是相同的。
如何对此进行改进呢。个人想法是:把ingpath的类型也改成指针类型,做为局部变量,每一次循环开始时都从新为ingpath指针指向的常量空间从新malloc一下,这样就保证了ingpath指向的内存地址每一次循环都被从新分配而不会相同,进而“解除”了与path所指向内存地址的绑定。这样的话,对ingpath指向的地址中的值进行修改就不会影响到path指向的地址中的值,保证了ingpath顺利存入path的相应位置。
按照这个思路,对代码进行了修改:

果不其然,输出path,正确的输出了全部文件的路径:
spa

总结

一个小问题,只须要修改一行代码就解决了的问题折腾了一天时间(此处,真的想发送一个围笑^_^)。不过期间没有白折腾,基本搞清楚了指针和数组相关的问题,收获良多,仍是很开心的。把这个debug的过程写出来做为一个分享。
最后,敲黑板:指针只是一个内存地址的引用,指向内存地址空间。若是在其余地方更变了这个地址空间里的数据,指针指向该地址空间中的值也会随之改变(废话,不都是一个值么)。debug

相关文章
相关标签/搜索