论坛首页 编程语言技术论坛

指针与数组的异同

浏览 29004 次
该帖已经被评为良好帖
作者 正文
   发表时间:2007-05-18  
C
指针是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中调用函数的时候会把实参进行拷贝,而如果实参是数组的话,拷贝的开销太大,所以不如指针方便.

呵呵,这边多维数组没有涉及到,不过多维数组只要紧记不过是数组的数组罢了.
   发表时间:2007-05-18  
hurricane1026 写道
s和s[0]竟然不同,为什么呢?
因为指针的访问和数组是不一样的,你可以看下我上面的那个解释。

char s[]="abc"; c=s[i]; 

编译器符号表有一个符号 s 地址为 1234,然后首先取i的值,把i和1234相加,然后取出(i+1234)的内容付给c.
0 请登录后投票
   发表时间: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]);
}
0 请登录后投票
   发表时间:2007-05-18  
只要是数组都是相同的,因为指针的话你需要先取出指针的地址然后再从这个地址取出内容(也就是指针所指的数组的第一个元素的地址),然后再取出这个地址的内容.
0 请登录后投票
   发表时间:2007-05-18  
hurricane1026 写道
s和s[0]竟然不同,为什么呢?
写程序测试了一下,对于char[]确实是这样,但是对于int[],double[]都是相同的。simon测试了么?

这个是我用gcc编译运行后的结果
2280676
4202496
2280672
2280672
貌似这个char *s只在栈里分配一个指针的空间,指向实际的字符串地址(这个字符串放在哪里的?  ),所以s和&s[0]的地址是不同的
而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),可能是因为优化的原因,具体就不清楚了
0 请登录后投票
   发表时间:2007-05-18  
呵呵,增加1 难道增加的不是 sizeof(char)吗? 你可以试试 int指针,看看他是增加多少.
0 请登录后投票
   发表时间:2007-05-18  
simohayha 写道
呵呵,增加1 难道增加的不是 sizeof(char)吗? 你可以试试 int指针,看看他是增加多少.

靠,快下班脑子坏了,其实看看上面s到s2的增长就能看出来,确实是增长了sizeof(char),丢人了……
0 请登录后投票
   发表时间:2007-05-18  
hurricane1026 写道
s和s[0]竟然不同,为什么呢?


s 和 s[0] 类型不同

char *s="abc"; 

&s --> char **
&s[0] --> char *

对于普通数组,s 应该和 &s[0] 相同
0 请登录后投票
   发表时间:2007-05-18  
xin_wang 写道
hurricane1026 写道
s和s[0]竟然不同,为什么呢?
写程序测试了一下,对于char[]确实是这样,但是对于int[],double[]都是相同的。simon测试了么?

这个是我用gcc编译运行后的结果
2280676
4202496
2280672
2280672
貌似这个char *s只在栈里分配一个指针的空间,指向实际的字符串地址(这个字符串放在哪里的?  ),所以s和&s[0]的地址是不同的


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返回的是个可能无效的地址(我是说可能,因为编译器可能那个时候没有覆盖这段内存)
0 请登录后投票
   发表时间: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内部,指向栈的引用是有效的
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics