LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 10964|回复: 51

C语言里面的指针和数组

[复制链接]
发表于 2003-6-13 23:45:14 | 显示全部楼层 |阅读模式
C语言里面很多地方指针和数组是可以互换使用的, 很多同学经常搞不明白. 大家可以把自己的理解写出来, 让论坛里的其他人看看, 既可以帮助别人,也可以让自己的错误及时纠正.

我说一个, 指针是可以赋值的, 但是数组只能初始化. 这是因为指针只记录了一个地址, 而数组是真的代表一块内存空间的.


  1. void myfunc()
  2. {
  3.     int a1[4] = { 1, 2, 3, 4 }; // OK, 初始化
  4.     int a2[4]; // OK, 未经初始化的数组
  5.     int* p1 = a1;

  6.     p1 = a2; // OK, 指针可以赋值
  7.     a2 = a1; // ERROR, 数组不能赋值
  8. }
复制代码
发表于 2003-6-14 00:44:59 | 显示全部楼层

回复: C语言里面的指针和数组

最初由 viper 发表

  1. void myfunc()
  2. {
  3.     int a1[4] = { 1, 2, 3, 4 }; // OK, 初始化
  4.     int a2[4]; // OK, 未经初始化的数组
  5.     int* p1 = a1;

  6.     p1 = a2; // OK, 指针可以赋值
  7.     a2 = a1; // ERROR, 数组不能赋值
  8. }
复制代码

我的理解是:
指针变量实际上就是一个地址,它指向某一个数值。比如:p1就是*p1的地址。p1+1就是*(p+1)的地址。改变指针的地址就改变了指针的指向。但数组就不能改变了。数组在编译的时候,还是改成指针的。
发表于 2003-6-14 01:46:29 | 显示全部楼层
嘿嘿~这帖子不错啊~想法真的很好~
我的理解(一下全是个人理解,如有错误,请指出):
指针里面存储的是地址,因此如果:

  1. int *i;
复制代码

那么i里面存储的是地址,是指针变量,所谓指针变量,就是这个变量中存储的是地址而不是具体数值;而运算符号*后面要跟一个指针变量或者地址常量——也就是要跟一个地址——它可以去寻找它后面地址中存储的内容,而*i就是代表:i所存储的地址中的内容——说起来比较饶嘴
我觉得理解指针数组最早应该理解:地址常量,指针变量,还有就是类型的声明。
地址常量和指针变量里面存储的都是地址,数组中的数组名是地址常量,指针变量前面已经说了。
至于类型的声明,比如:
int i;那么,i就是一个int类型,同理:int *i;那么*i就是一个int类型,还有:int fun();那么fun()就是一个int类型,即:是一个返回值为int类型的函数。
都是个人理解,难免有错~
发表于 2003-6-14 09:08:40 | 显示全部楼层
来一段林锐的C/C++编程指南吧,说得比较清楚:

  1. 7.3指针与数组的对比
  2.         C++/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。
  3.         数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。
  4. 数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,
  5. 只有数组的内容可以改变。
  6. 指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指
  7. 针来操作动态内存。指针远比数组灵活,但也更危险。
  8. 下面以字符串为例比较指针与数组的特性。

  9. 7.3.1 修改内容
  10.         示例7-3-1中,字符数组a的容量是6个字符,其内容为hello\0。a的
  11. 内容可以改变,如a[0]= ‘X’。指针p指向常量字符串“world”(位于静态
  12. 存储区,内容为world\0),常量字符串的内容是不可以被修改的。从语法上
  13. 看,编译器并不觉得语句p[0]= ‘X’有什么不妥,但是该语句企图修改常量
  14. 字符串的内容而导致运行错误。

  15.   char a[] = “hello”;
  16.   a[0] = ‘X’;
  17.   cout << a << endl;
  18.   char *p = “world”;     // 注意p指向常量字符串
  19.   p[0] = ‘X’;                   // 编译器不能发现该错误
  20.   cout << p << endl;

  21. 示例7-3-1 修改数组和指针的内容

  22. 7.3.2 内容复制与比较
  23.         不能对数组名进行直接复制与比较。示例7-3-2中,若想把数组a的内
  24. 容复制给数组b,不能用语句 b = a ,否则将产生编译错误。应该用标准库函
  25. 数strcpy进行复制。同理,比较b和a的内容是否相同,不能用if(b==a) 来判
  26. 断,应该用标准库函数strcmp进行比较。
  27.         语句p = a 并不能把a的内容复制指针p,而是把a的地址赋给了p。要
  28. 想复制a的内容,可以先用库函数malloc为p申请一块容量为strlen(a)+1个字
  29. 符的内存,再用strcpy进行字符串复制。同理,语句if(p==a) 比较的不是内
  30. 容而是地址,应该用库函数strcmp来比较。

  31.   // 数组…       
  32.   char a[] = "hello";       
  33.   char b[10];       
  34.   strcpy(b, a);                        // 不能用       
  35.   b = a;       
  36.   if(strcmp(b, a) == 0)        // 不能用  if (b == a)
  37.   …

  38.   // 指针…       
  39.   int len = strlen(a);       
  40.   char *p = (char *)malloc(sizeof(char)*(len+1));       
  41.   strcpy(p,a);                        // 不要用 p = a;       
  42.   if(strcmp(p, a) == 0)        // 不要用 if (p == a)
  43.   …

  44. 示例7-3-2 数组和指针的内容复制与比较


  45. 7.3.3 计算内存容量
  46.         用运算符sizeof可以计算出数组的容量(字节数)。示例7-3-3(a)
  47. 中,sizeof(a)的值是12(注意别忘了’\0’)。指针p指向a,但是sizeof(p)
  48. 的值却是4。这是因为sizeof(p)得到的是一个指针变量的字节数,相当于
  49. sizeof(char*),而不是p所指的内存容量。C++/C语言没有办法知道指针所指
  50. 的内存容量,除非在申请内存时记住它。
  51. 注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。示
  52. 例7-3-3(b)中,不论数组a的容量是多少,sizeof(a)始终等于sizeof(char *)。

  53.   char a[] = "hello world";       
  54.   char *p  = a;       
  55.   cout<< sizeof(a) << endl;        // 12字节       
  56.   cout<< sizeof(p) << endl;        // 4字节

  57. 示例7-3-3(a) 计算数组和指针的内存容量

  58. void Func(char a[100])        {               
  59.   cout<< sizeof(a) << endl;        // 4字节而不是100字节
  60. }

  61. 示例7-3-3(b) 数组退化为指针
复制代码
 楼主| 发表于 2003-6-14 10:26:35 | 显示全部楼层
char a[] = “hello”;
  a[0] = ‘X’;
  cout << a << endl;
  char *p = “world”;     // 注意p指向常量字符串
  p[0] = ‘X’;              // 编译器不能发现该错误
  cout << p << endl;

应该在可能的时候尽量使用 const. 比如可以写
const char* p = "Hello world";
编译程序就能发现错误了。

即使不用 const ,GCC也能给出一个警告
发表于 2003-6-14 10:34:15 | 显示全部楼层

> p1+1就是*(p+1)的地址。
应该是:p1+1是*(p1+1)的地址,是0100兄的笔误吧。

其实上面所讨论里有很多书已经写得很清楚了,比如《C程序设计》(谭浩强)
发表于 2003-6-14 12:20:18 | 显示全部楼层
是的。是我的错。
cout << a << endl;
是不是C++的?
 楼主| 发表于 2003-6-14 19:25:19 | 显示全部楼层
p+1是*(p+1)的地址,本来是*(p+1)是p+1指向的内容,反过来说感觉优点怪呢。
p+1 到底加了多少,要看 p 是指向什么类型的指针,比如(char*) 和 (int*)。
发表于 2003-6-14 23:04:17 | 显示全部楼层

:)

当然,是有条件的,如果指出范围就不行了。是void也不行。
 楼主| 发表于 2003-6-15 10:59:43 | 显示全部楼层
void* p = 0;
p ++;

是可以编译过的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表