数组与指针
我们先来看一个简单的小例子:
//test.c
int mango[100]={1,2,3,4,5,6,7,8,9,0};
//main.c
#include<stdio.h>
//extern int mango[];
extern int *mango;
int main(void)
{
printf("%d:%d\n",*mango,(*mango+3)); //运行结果会是什么?
return 0;
}
然后编译运行看看执行结果是多少?
结果是产生了,coredump文件,对内存访问操作发生了问题。
然后我们看另一种方式:
//test.c
int mango[100]={1,2,3,4,5,6,7,8,9,0};
//main.c
#include<stdio.h>
extern int mango[];
//extern int *mango;
int main(void)
{
printf("%d:%d\n",*mango,(*mango+3)); //运行结果会是什么?
return 0;
}
打印出来了结果1和4,所以说数组和指针在某些时候是不相等的。
区别
指针 | 数组 |
---|---|
保存数据的地址 | 保存数据 |
间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。如果指针有一个下标[I],就把指针的内容加上I作为地址,从中提取数据。 | 直接访问数据,a[I]只是简单地a+I为地址取得数据 |
通常用于动态数据结构 | 通常用于存储固定数目且数据类型相同的元素 |
相关的函数为malloc(),free() | 隐式分配和删除 |
通常指向匿名数据 | 自身即为数据名 |
数组和指针都可以在它们的定义中用字符串常量进行初始化。看上去一样,但底层的机制却不相同。
定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针本身的空间,除非在定义时同时赋给指针一个字符串常量进行初始化。例如,下面的定义创建了一个字符串常量(为其分配了内存):
char *p = "breadfruit";
注意只有对字符串常量才是如此。不能指望为浮点数之类的常量分配空间,如:
float *pip = 3.141; // 错误,无法通过编译
在ANSI C中,初始化指针时所创建的字符串常量被定义为只读。如果试图通过指针修改这个字符串的值,程序就会出现未定义的行为。在有些编译器中,字符串常量被存放在只允许读取的文本段中,以防止它被修改。
我们先来看看正确的运行结果:
#include<stdio.h>
#include<string.h>
//extern int mango[];
//extern int *mango;
//double *pip = 3.141;
char *p = "breadfruit";
int main(void)
{
//printf("%d:%d\n",*mango,(*mango+3)); //运行结果会是什么?
printf("%s\n",p);
//strncpy(p,"food",4);
//printf("%s\n",p);
//printf("%f\n",*pip);
return 0;
}
然后我们在看看异常的结果:
#include<stdio.h>
#include<string.h>
//extern int mango[];
//extern int *mango;
//double *pip = 3.141;
char *p = "breadfruit";
int main(void)
{
//printf("%d:%d\n",*mango,(*mango+3)); //运行结果会是什么?
printf("%s\n",p);
strncpy(p,"food",4);
printf("%s\n",p);
//printf("%f\n",*pip);
return 0;
}
出现了段错误,这也就验证了上面的结论,不能通过指针修改字符串常量。
数组也可以用字符串常量进行初始化:
char a[]="gooseberry";
但与指针相反,由字符串常量初始化的数组是可以修改的。其中的单个字符在以后可以改变,比如:
#include<stdio.h>
#include<string.h>
char p[] = "gooseberry";
int main(void)
{
printf("%s\n",p);
strncpy(p,"black",5);
printf("%s\n",p);
return 0;
}
可以修改。