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

指针与数组的异同

浏览 29003 次
该帖已经被评为良好帖
作者 正文
   发表时间: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是一个字符串常量

其实我就是不确定是不是有常量区这个概念
惭愧啊
0 请登录后投票
   发表时间:2007-05-19  
刑天战士 写道


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返回的是个可能无效的地址(我是说可能,因为编译器可能那个时候没有覆盖这段内存)


字符串应该是个隐式的static吧?
因为a[]是个自动变量,一出这个函数体,这个变量就会被销毁,此时谁也不知道a所指的内容是什么,那块内存不知道什么时候会被覆盖.
0 请登录后投票
   发表时间:2007-05-20  
the truth is that c89 requires compilers to put char *a="aaaaa"; into .text segment.
now you should know why it can never be ruined by other stack frames, and why any attempt of modifying the content of the string will trigger segment fault.
0 请登录后投票
   发表时间:2007-05-21  
不可以把数组名字作为左值运算
其他情况下基本一样的吧。
0 请登录后投票
   发表时间:2007-05-22  
simohayha 写道
。下标总是和指针偏移量相同,a[i]总是被编译器改写成*(a+i)这种形式来访问。(比如:a[6]和6[a]是一样的)


可能是我专牛角尖了

*(a+i)通常会计算为a+T*i,这里T是数组存放的数据类型的大小。
“a[6]”和“6[a]”通常是不一样的
0 请登录后投票
   发表时间:2007-05-22  
simohayha 写道
指针是c的灵魂,俺这里只能抛砖引玉了.

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

编译器符号表有一个符号s,他的地址为1234,然后取地址1234的内容,就是'5678',然后把i和5678相加,然后取出(i+5678)的内容付给c.


实际上可以这么理解,变量的名称对应了内存的一块区域。对于普通变量如 int i = 1,i 对应的内存存储的值就是“1”,而对于指针类型的变量 char *s = "abc",s对应内存存储的值实际上是一个地址,通过该地址可以引用到实际的值(也就是书上说的“指向xxx”)。
用simohayha上面的例子:s存储的东西是'5678',这个地址就是字符串“abc”的实际存放位置。而s本身也是有地址的,通过 &s得到的就是'1234'
0 请登录后投票
   发表时间:2007-05-22  
Spike 写道
simohayha 写道
。下标总是和指针偏移量相同,a[i]总是被编译器改写成*(a+i)这种形式来访问。(比如:a[6]和6[a]是一样的)


可能是我专牛角尖了

*(a+i)通常会计算为a+T*i,这里T是数组存放的数据类型的大小。
“a[6]”和“6[a]”通常是不一样的

这里是你理解错了,在这边你所说的T是编译器进行判定的而不是我们来决定的,比如这边a[i]只是说从a所指的地址开始,前进i步,每步都是一个数据类型(也就是数组所存的数据类型),在这边每步的大小是编译器进行判断的。a[6]和6[a]编译器会自行判断 那个是数组名,那个是所要前进的步数.
0 请登录后投票
   发表时间:2007-05-22  
以下是从《C专家编程》里总结出来的三条,加上了个人见解。

1.当数组整体作为参数传递时,数组被当成一个指针传递。于是,在被调用函数中,数组就是指针。
2.作为整体考虑时,数组就是数组,指针就是指针,两者不中互换。
  2.1.数组声明时,指针与数组不可互换。包括数组的定义,声明,与extern声明,都不可互换。
  2.2.应用于sizeof操作时,两者不可互换。
3.在引用数组单个元素的时候,数组仍然是数组,两者虽然本质不同,但是表现得跟const指针一样。因此如果arr是一个指针,在arr[i]中,arr可以用指针替换,不能改变arr的值,如++arr是不允许的。
0 请登录后投票
   发表时间:2007-05-22  
林杰杰 写道
以下是从《C专家编程》里总结出来的三条,加上了个人见解。
1.当数组整体作为参数传递时,数组被当成一个指针传递。于是,在被调用函数中,数组就是指针。
2.作为整体考虑时,数组就是数组,指针就是指针,两者不中互换。
  2.1.数组声明时,指针与数组不可互换。包括数组的定义,声明,与extern声明,都不可互换。
  2.2.应用于sizeof操作时,两者不可互换。
3.在引用数组单个元素的时候,数组仍然是数组,两者虽然本质不同,但是表现得跟const指针一样。因此如果arr是一个指针,在arr[i]中,arr可以用指针替换,不能改变arr的值,如++arr是不允许的。


这里总结得很好。有几点要补充的:
1、数组有单独的空间,一般就是 数组下标个数×sizeof(类型),例如在 32 位 intel 处理器上,char[10] 占用 10×1=10 字节空间。但因为数据需要对齐的原因,实际会占用 10+2 字节,因为要按处理器字长 4字节 对齐。
2、指针的大小一般就是机器地址总线长度,例如在 32 位 intel cpu 上就是 4 字节长。
3、空数组只是一个符号,不占内存空间。例如
struct udphdr {
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
  char tag[0];
  char data[100];
};
struct udphdr udp;

这里,tag 不占内存,只表示 &((char*)&udp+8) 的内存地址位置,
&udp.tag == &((char*)&udp + 8 ) == &udp.data

所以
char tag[0];
通常用以标记 struct 中某一特定内存位置。
0 请登录后投票
   发表时间:2007-05-22  
homejet 写道
指针好难懂啊 ,最近正在看一本电子书<c和指针> www.51leifeng.net/thread-655-1-1.html,有兴趣的朋友可以去看看挺好的 大家可以一起交流啊


C and Pointer 是一本好书。不过事实上,更推荐多写代码,特别是 socket 编程,会更多的涉及到指针。写代码比单看书有用多了。
0 请登录后投票
论坛首页 编程语言技术版

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