|
锁定老贴子 主题:指针与数组的异同
该帖已经被评为良好帖
|
|
|---|---|
| 作者 | 正文 |
|
时间:2007-05-18
指针是c的灵魂,俺这里只能抛砖引玉了.
1 首先,数组名不能当作赋值对象,比如下面的代码:
char *s="abc";
char *s1="bcd";
s1=s;
printf("%c\n",s1[0]);
可以正常运行,如果把 这边的指针变为数组就会出错。
2 下面阐述一下,指针和数组各自是如何访问的: char s[]="abc"; c=s[i]; 编译器符号表有一个符号 s 地址为 1234,然后首先取i的值,把i和1234相加,然后取出(i+1234)的内容付给c. char *s="abc"; c=s[i]; 编译器符号表有一个符号s,他的地址为1234,然后取地址1234的内容,就是'5678',然后把i和5678相加,然后取出(i+5678)的内容付给c. 大家可以看下下面的这个程序:
#include <stdio.h>
void main()
{
char *s="abc";
char s2[]="789";
printf("%d\n",&s);
printf("%d\n",&s[0]);
printf("%d\n",&s2);
printf("%d\n",&s2[0]);
}
呵呵,s和s[0] 的地址竟然不一样。 3 定义指针时编译器并不为指针所指向的内容分配空间,它只分配指针本身的空间,除非在声明的同时付给指针一个字符串常量初始化。比如: char *s="abc"; 可是只有对字符串常量才是如此,其他的类型都会出错。 4 数组和指针的相同点。 。表达式中的数组名(不同于声明)被编译器当做一个指向数组第一个元素的指针。 。下标总是和指针偏移量相同,a[i]总是被编译器改写成*(a+i)这种形式来访问。(比如:a[6]和6[a]是一样的) 。在函数参数的声明中,数组名被编译器当做一个指向数组第一个元素的指针 可以看下下面的代码的输出。
#include <stdio.h>
void f(char s[]);
void g(char *s);
char s2[4]="789";
void main()
{
printf("%d\n",&s2);
printf("%d\n",&(s2[0]));
f(s2);
g(s2);
}
void f(char s[4])
{
printf("%d\n",&s);
printf("%d\n",&(s[0]));
}
void g(char *s)
{
printf("%d\n",&s);
printf("%d\n",&s[0]);
}
为什么c要做成这种呢,其实很简单,就是在c中调用函数的时候会把实参进行拷贝,而如果实参是数组的话,拷贝的开销太大,所以不如指针方便. 呵呵,这边多维数组没有涉及到,不过多维数组只要紧记不过是数组的数组罢了. 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
时间:2007-05-18
hurricane1026 写道 s和s[0]竟然不同,为什么呢? 因为指针的访问和数组是不一样的,你可以看下我上面的那个解释。
char s[]="abc"; c=s[i]; 编译器符号表有一个符号 s 地址为 1234,然后首先取i的值,把i和1234相加,然后取出(i+1234)的内容付给c. |
|
| 返回顶楼 | |
|
时间:2007-05-18
int ,double也是不同的。
#include <stdio.h>
void main()
{
int s[]={1,2,3};
int *d=s;
printf("%d\n",&d);
printf("%d\n",&d[0]);
}
|
|
| 返回顶楼 | |
|
时间:2007-05-18
只要是数组都是相同的,因为指针的话你需要先取出指针的地址然后再从这个地址取出内容(也就是指针所指的数组的第一个元素的地址),然后再取出这个地址的内容.
|
|
| 返回顶楼 | |
|
时间:2007-05-18
hurricane1026 写道 s和s[0]竟然不同,为什么呢?
写程序测试了一下,对于char[]确实是这样,但是对于int[],double[]都是相同的。simon测试了么? 这个是我用gcc编译运行后的结果 2280676 4202496 2280672 2280672 貌似这个char *s只在栈里分配一个指针的空间,指向实际的字符串地址(这个字符串放在哪里的? 而char[]是在栈里分配一个字符串,所以&s2[0]和s2的地址是同一个。 在那个程序后面加几行:
printf("%d\n",&s2[1]);
printf("%d\n",&s2[2]);
printf("%d\n",&s2[3]);
就能观察到这个字符串的在栈中的地址是在往下增长的: 2280676 4202496 2280672 2280672 2280673 2280674 2280675 但是好像不是不是往下增长一个sizeof(char)而是一个sizeof(int),可能是因为优化的原因,具体就不清楚了 |
|
| 返回顶楼 | |
|
时间:2007-05-18
呵呵,增加1 难道增加的不是 sizeof(char)吗? 你可以试试 int指针,看看他是增加多少.
|
|
| 返回顶楼 | |
|
时间:2007-05-18
simohayha 写道 呵呵,增加1 难道增加的不是 sizeof(char)吗? 你可以试试 int指针,看看他是增加多少.
靠,快下班脑子坏了,其实看看上面s到s2的增长就能看出来,确实是增长了sizeof(char),丢人了…… |
|
| 返回顶楼 | |
|
时间:2007-05-18
hurricane1026 写道 s和s[0]竟然不同,为什么呢?
s 和 s[0] 类型不同 char *s="abc"; &s --> char ** &s[0] --> char * 对于普通数组,s 应该和 &s[0] 相同 |
|
| 返回顶楼 | |
|
时间:2007-05-18
xin_wang 写道 hurricane1026 写道 s和s[0]竟然不同,为什么呢?
写程序测试了一下,对于char[]确实是这样,但是对于int[],double[]都是相同的。simon测试了么? 这个是我用gcc编译运行后的结果 2280676 4202496 2280672 2280672 貌似这个char *s只在栈里分配一个指针的空间,指向实际的字符串地址(这个字符串放在哪里的? char* s="xxxxxx"; s的实际地址指向常量区的值为xxxxxx的地址,也就是说,s是一个字符串常量 看这段:
#include <stdio.h>
#include <stdlib.h>
char* s1();
char* s2();
int main()
{
printf("%s",s1());
printf("%s",s2());
}
char* s1()
{
char *a="aaaaa";
return a;
}
char* s2()
{
char a[]="bbbbbbb";
printf("%s",a);
return a;
}
s1的方法返回的是正确的字符串,s2就不敢保证了,因为他的char a[]="bbbbbbb";只是在当前栈中,a返回的是个可能无效的地址(我是说可能,因为编译器可能那个时候没有覆盖这段内存) |
|
| 返回顶楼 | |
|
时间:2007-05-18
看这段:
#include <stdio.h>
#include <stdlib.h>
char* s1();
char* s2();
int main()
{
printf("%s",s1());
printf("%s",s2());
}
char* s1()
{
char *a="aaaaa";
return a;
}
char* s2()
{
char a[]="bbbbbbb";
printf("%s",a);
return a;
}
s1返回的是正确的字符串,因为s1引用的是不变的常量区;s2则是引用的栈的内存,所以s2有可能出现不正确的结果(在我的gcc上,是乱码),但是在s2内部没有问题,因为在s2内部,指向栈的引用是有效的 |
|
| 返回顶楼 | |








