#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<vld.h> //测试内存泄漏
#include<stdlib.h>
#include<vld.h> //测试内存泄漏
int main()
{
{
char buf[100]; //从键盘读取字符串
char *arr[3]; //存放指针的数组,指向地址
int i;
char *arr[3]; //存放指针的数组,指向地址
int i;
/*
浅拷贝:多个指针指向同一段内存
// 字符串常量属于浅拷贝,所以不能被修改
for(i=0;i<3;i++)
{
scanf("%s",buf);
// 字符串常量属于浅拷贝,所以不能被修改
for(i=0;i<3;i++)
{
scanf("%s",buf);
arr[i]=buf;
}
for(i=0;i<3;i++)
{
printf("%s\n",arr[i]);
}
*/
}
for(i=0;i<3;i++)
{
printf("%s\n",arr[i]);
}
*/
测试:
输入:
aaa
bbb
ccc
输出:
ccc
ccc
ccc
想要输出的是aaa bbb ccc,但是实际输出的却是 ccc ccc ccc,就是因为浅拷贝的问题,arr是一个指针数组,存放的是buf的地址,buf的地址是恒定的,假设是1000,那循环三次都是1000,但是里面的内容发生了改变,原来是aaa,但是再输入bbb的时候,就覆盖了aaa,同样ccc也覆盖了bbb,所以最后buf里面存放的只有ccc,而arr是buf的地址1000,所以每次存进去的都是1000,输出数组的时候,就全是ccc了。这就是浅拷贝,实质就是多个指针指向同一段内存。
scanf从输入留缓冲区读取数值,如果输入缓冲区有数,它就可以用,没有数值或者数值不足,就要等待。缓冲区的数是从键盘缓冲区里来的。键盘缓冲区的数据只有遇到回车才送入输入流缓冲区,否则留在键盘缓冲区,不会到输入流缓冲区。所以scanf并不是一定要等回车,scanf只是等输入流缓冲区有数取,键盘一次输入很多数,回车,输入流缓冲区就有很多数了。scanf读数以空白为数的分隔符,空格,回车属于空白,回车对于scanf来说,只是数的分隔符而已。
//深拷贝:每个指针指向单独的内存
如果想要把输入的值都输出来怎么办,首先就是要创建一个和输入字符相等长度的数组保存这个字符串,再将键盘读取的数据拷贝到新的数组中去,然后数组arr的值保存新数组的地址,就可以对它们分别进行访问了。这就是深拷贝,每个指针指向单独的内存。
for(i=0;i<3;i++)
{
scanf("%s",buf);
//1.计算字符串长度
//2.动态创建内存
arr[i]=(char *)malloc(sizeof(char)*(strlen(buf)+1));
//3.拷贝数据
strcpy(arr[i],buf);
//2.动态创建内存
arr[i]=(char *)malloc(sizeof(char)*(strlen(buf)+1));
//3.拷贝数据
strcpy(arr[i],buf);
/* 也可以这样写
char *p=(char *)malloc(sizeof(char)*(strlen(buf)+1));
strcpy(p,buf);
arr[i]=p;
*/
}
char *p=(char *)malloc(sizeof(char)*(strlen(buf)+1));
strcpy(p,buf);
arr[i]=p;
*/
}
for(i=0;i<3;i++)
{
printf("%s\n",arr[i]);
}
{
printf("%s\n",arr[i]);
}
for(i=0;i<3;i++)
{
free(arr[i]); //每个都要销毁
arr[i]=NULL; //防止野指针
}
{
free(arr[i]); //每个都要销毁
arr[i]=NULL; //防止野指针
}
return 0;
}
}