数组和指针是很让人敬畏的话题,我只是谈下个人理解和总结:
一、数组和指针的内存分配
数组的内存分配,一维数组和多维数组都是线性分配内存。一个一维数组char a[n] = “abcdefgh”的内存分配模型如下图。
a = 9980,并且分配一个内存空间来存储a。这正是数组和指针内存分配的区别之处。
指针的内存分配,定义char *p = “abcdefgh”。会为p分配一个内存空间,存储字符串的首地址。正是一般指针的概念。内存分配模型如下图。
这里需要注意的是:
char *pc = “abcdefgh”; // 定义了一个字符串常量,不能通过引用p来改写
*(p + 1) = ‘g’; //运行时提示错误,内存不能被写
char pp[] = “abcdefg”;
*(pp + 1) = ‘g’; // ok
并且只有字符串数组可以这样定义,如果是int类型数组就不能编译通过了。
int *pi = {1, 2, 3}; //编译错误
如果是多维数组会怎样呢?
char *pc[3] = {“ni”, “hao”, “!”}; //没问题
int *pi[3] = {{1},{1, 2}, {1, 2, 3}}; //编译错误
后者的解决办法是分解为3个一维数组
int *p1 = {1};
int *p2 = {1,2};
int *p3 = {1,2,3};
int *pi[3] = {p1, p2, p3}; // ok
字符指针的另一个用处是把局部变量的指针当做返回值
char* func()
{
char* p = “abcdefg”;
return p;
}
int main()
{
cout << func() << endl;
return 0;
}//能正确输出”abcdefg”
如果字符串改成数组定义方式
char* func()
{
char p[] = “abcdefg”;
return p;
}
int main()
{
cout << func() << endl;
return 0;
}//输出的会是乱码
二、数组与指针的全局变量声明
文件1中的全局变量
char p[] = “abcdefgh”;
文件2中的声明方式
extern char *p; //调用时会出错
extern char p[];//ok
前者错误的原因是,编译器会把字符数组的第一个元素理解为地址。不出错才怪!!
相对应的情况
文件1中的全局变量
char *p = “abcdefgh”;
文件2中的声明方式
extern char *p; //ok
extern char p[];//调用时会出错
或者错误的原因是,编译器会将p中的内容(地址)理解为了字符。
三、二者的蛋疼区别
对于定义
char* p = “abcdef”;
char pp[] = “abcdef”;
sizeof(p);//打印输出结果为4
sieof(pp);//打印输出结果为6
++ p;//ok
printf(“%s\n”, p);//输出bcdef
++pp;//编译错误,同样不能当做赋值运算的左值,是个常量啊
四、编译器实现“大同“
定义如下
char* p = “abcdefg”;
char pp[] = “abcdefg”;
cout << &p << endl;
cout << &pp << endl;
两者都会输出数组的首地址,编译器会将其理解为指针。
同样发生将函数参数声明为指针或数组的情况。
void func(char* p){//do something}
void func(char p[]){//do something}
两者作用完全一样。
还体现在对数组元素的存取操作
p[1];
*(p + 1);
pp[1];
*(pp + 1);
都能完美运行。