鱼C论坛

 找回密码
 立即注册
查看: 16147|回复: 64

[技术交流] 关于指针和数组,二级指针,数组指针,指针数组,发表下个人见解,大家互相交流下。。

  [复制链接]
发表于 2012-5-26 20:13:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
                         首先,在C语言中,最难的就是定义变量,给变量赋值。其实所有的C程序拉出来看到的都是在定义变量,给变量赋值,中间的程序通过运算得到的结果,也可以算是给变量赋值。
                        (一)先说定义变量:
                          因为变量名都是自己定义的标示符,然后最重要的就是变量的类型了。虽然大多C语言书上 都列举出了众多的数据类型,但是个人理解,那些都是最基本的一些东西,其实还有很多中类型 我们经常遇到,却不知道 这些还是数据的类型。

                        一,指针类型;
                          int *     ,short *  ,char *,     int **,char**,   long int ****************;

                        这些都是指针类型,很显然,可以看出 指针类型就是在基本数据类型前面加个*  ,  例如定义一个指针变量,
                       int *       p;             这个变量p,就有两种含义,第一是,这是一个指针变量,第二是他指向int类型。       我们都知道对于32位pc机,  指针变量都是四个字节。        int **    p;对于变量p,  也有两个含义,第一这是一个指针变量,第二,它指向一个int*类型.
                           二,数组类型。
                         这里估计,有人就质疑了,C语言里面还有数组类型吗?  有。并且我们一直在写,一直在用,我们一直不知道,是因为C语言的书写方式导致我们不知道有这种类型。  对于一个一维数组,    int   a[10];    C语言的书是这样解释这个东西的,这是个一维数组,也就是一次性定义了十个变量。  在内存中呈线性排列。。。。。。 其实我个人理解这个东西应该这样定义,这是一(个包含10个int  元素的 类型的)  变量。我们在描述一个变量的时候,总说,这是一个XXX类型的变量,所以在这里对于int   a[10];应该这样描述,这是一个有10个int元素的 类型的  变量a;  所以写成  这样   int [10]         a;         这是一个变量但是它包含十个元素,这是不是跟我们学过的一个东西特别像?    结构体, 结构体不就是包含里XXX 元素的类型 ,然后用这种类型定义了一个变量,叫做结构体变量。  C语言给结构体类型起名字了,却没给数组类型起名字,所以我们不知道。但是定义数组的时候写成
int [10]      a; 这样 很多编译器 都编译不通过,或者说没有编译器认识它,之所以这样写,只是要明白,数组的原理,因为后面对于能正确理解数组指针,至关重要。。。。

                       三,指针数组;
                      指针数组很简单,就是int *    a[10];      类型换了一下而已,按照上面的解释更直观一点写成int *[10]         a;  这样,就可以解释为,定义了(一个包含10个指针类型元素的 )这种类型的变量     a;

                      四,数组指针,

                     若看完了上面对于数组类型的 解释以后,对于数组指针是不是已经很简单了。 定义一个指针数组类型的变量   是
   int *  a[10];前面说了 ,更直观的写成:

       int*[10]        a;     那么定义一个指针变量,就是在原有类型前面加一个*,  也就是int* [10] *      p;    但是C语言里面不能这样写, 规定要把[10]   写到后面,所以就成了int *  *  p[10];   但是现在这样就有个问题了,之前有个[10]在中间隔开,倒是可以区别,(int *[10])*     p;  现在[10]  写到了后面,无法区别这两个*,到底属于那边的,加空格没作用,所以只能加最有权威的分隔符()  那么就成了 int *  (*p)[10];  这里定义了一个指向(有10个int*类型元素的数组)的类型的 变量  p;

           不好意思,这里有些太绕口,不好理解,确实不好理解,之所以不好理解,是因为我们书写习惯了,看习惯了目前C的这种书写形式,对一些东西根深蒂固。就像很多新人最开始学习指针的时候都是这样定义的,int     *p;  这样写虽能编译通过,但是他已经把指针理解错了, 指针不就是一个普通变量,int *   p;  就是一个变量p,类型是 int *类型。。......对于学习C语言的新人,要永远记住,对于任何变量,都是某某某类型    的  一个变量。      这个类型可以是任何类型。 不光是书上的那几种类型,有很多类型都是我们自己定义的,例如int ********   这种类型。


                   上面说了这么多,最重要的是最近看到前面有几个帖子对于指针和数组。有很多新人都很纠结,这个东西理解很容易进入误区,因为这所有东西都是建立在编译器的前提下的。或许你理解的是对的,但是编译没通过,你会认为这是错的,其实没必要理解是一回事,编译是另一回事;;
                    五;关于数组和数组名,以及数组指针赋值。

                     对于一维数组  int a[10]; 它有10个int 类型的元素   在内存单元中呈线性排列,首元素的地址就是这个数组的首地址,也就是 &a[0], 但是C语法规定可以简写成a; 就在这里出现了一个严重的问题,我之前说的 int  a[10];  等于是个int [10]     a;
通俗一点说就是int [10] 类型的变量  a;所以a的类型就是  int [10], 这就是为什么printf("%d\n",sizeof(a));会打印出40,因为a 是一个拥有十个元素的数组类型的变量。但是前面说了C语法里面吧&a[0]简写成a;
用过指针的童鞋应该都知道 对于XXX类型的变量,前面加个&。(&变量名)这就是一个表达式了,而这个表达式的类型就是这个变量原来的某某某类型加个*   就是XXX*类型,所以&a[0]  的类型就是int *类型了 ,所以定义一个指针变量,int *    p=&a[0];  //p=a;这样都正确,{(但是按照我的理论,p=a;能编译通过,a的类型是int [10]  类型,p是int* 类型,p=a能编译通过不是偶然而是必然,绝不是因为a是&a[0]的简写,而是我个人认为int[10]  跟int* 类型本来就匹配。是同一种类型(推理过程下文有详解))},因为赋值两边类型匹配。无可厚非都是int *类型。   若定义一个数组指针 int (*p)[10],   这里p的类型是int (*)[10]    按我之前的书写方式就是int [10]  * ;这种类型,很直观.对于数组 int a[10],  刚才说了 a的类型是 int[10],  所以&a这个表达式的类型就是 int[10]*类型的。所以 int a[10];  int (*p)[10];  p=&a;  这样可以赋值,因为两边类型匹配,无可厚非。这不是谁规定的,真理都是有根据的。。。  

               下面解释下二维数组;在说二维数组之前,先解释下刚才留下的那个问题:就是int [10]   这个类型跟int *类型为什么匹配的问题,对于一维数组int[10]   a;   int b;   b=*a;    这样没有问题吧,那就说明*a的类型跟b的类型一致,都是int 类型,a的类型本来是int [10]      *a就成了int 类型.。大家都知道 只有对于一个指针变量,也就是带*号的类型的表达式 才可以(*非常量表达式),这样之后表达式的类型就变成原来的类型去掉一个*,例如int ***   m;   *m的类型就是 int**.     想必这大家都知道吧。回到原题
a是int [10]  类型的,*a成了int 类型,所以int[10] ,也可以看成是int *类型,两者“本是同根生,书写却不同”。这就很明了为什么:

int a[10];   int *    p=a;这样了。

             对于二维数组 int a[5][10];  可以写成int [10]      a[5];     继续  (int [10])[5]     a;这里 的小括号至关重要,我这样写可能大家一时半会反应不过来,但是你若认真的看完了前面我对一维数组的解释之后,并且看懂的话这个就不难看懂。 我只所以再不用通俗语言去解释这个东西,是因为C里面不能这样写,并且没有给这种东西起名字,不像结构体,结构体数组。都有名字,其实这个跟结构体就是一回事,都是个大变量,里面包含很多元素。同一个道理的,闲话不扯,入正题。前面刚解释了对于XXX[]这种类型跟XXX*这种类型是相同的。那么a的类型是 (int [10])[5]  ,也就是int [10] *类型。  这又让我们回想起了一个东西,什么呢?数组指针,int (*p)[10];    这里p的类型是int (*)[10] ,按我书写方式就是int [10] *,这不是跟a的类型匹配了吗?所以对于代码:

  int a[5][10];
  int (*p)[10];
  p=a;    这样可以直接赋值,因为类型匹配,无可厚非。。。。不是老师说的,也不是书上说的,这不是规定的。要相信世间万物必有其存在的道理。。。。。。。。。。。。。

         某不才,仓促间用了几个小时完成了这篇文章,里面肯定漏洞百出,若那位兄弟看到可告知某,某不甚感激。。。。。。另外上述纯属个人理解,若那位兄弟有其他的更好的解释,愿分享交流。

评分

参与人数 4荣誉 +20 鱼币 +20 贡献 +7 收起 理由
破灬王 + 5 + 5 + 2 支持楼主!
小布丁 + 6 + 6 支持原创!
丿夏夜灬彬刂 + 5 + 5 + 5 很给力!
湮汐 + 4 + 4

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
头像被屏蔽
发表于 2012-5-31 11:08:43 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-5-31 11:17:18 | 显示全部楼层
C指针的精华。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-5-31 11:35:53 | 显示全部楼层
赵昕比老唐说的还清楚
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-5-31 13:38:02 | 显示全部楼层
理解的很好,但是有错误
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-6-1 15:13:48 | 显示全部楼层

有个很严重的错误,可以说这个错误是个致命的,也是最关键的,目前任无法解释。。。    遗憾啊,希望不要误导了别人。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-6-1 18:35:59 | 显示全部楼层
嗯,说得不错,很好。不过就事论事,LZ对数组名和指针的关系那段真的是扯淡。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
 楼主| 发表于 2012-6-3 11:34:01 | 显示全部楼层
仰望天上的光 发表于 2012-6-1 18:35
嗯,说得不错,很好。不过就事论事,LZ对数组名和指针的关系那段真的是扯淡。

C版主出来批判了。。。     上述帖子确实后面那里存在很严重的漏洞。。。 那天时间仓促。。。不过C里面存在很多无法解释的问题。例如 int a[0];   int *   p;   p=a;  这里编译器通过的,但是若printf("%d\n",sizeof(0)); 会打印出40;p的类型是int*类型,若a相当于&a[0]  那么a的类型是也是Int*类型,四个字节,为什么打印出40呢? 若按我的理解a的类型是int [10]  类型,printf("%d\n",sizeof(0)); 能解释通,p=a;就解释不通; 还有二维数组int a[10][10] ;int * p=a[0];   printf("%d\n",sizeof(a[0]));  这里也能打印出40,说明a[0] 的类型也是
int [10]  类型, 但是p的类型是int *类型。为什么这样赋值编译能通过?  如果对于一维数组a相当于&a[0]   对于二维数组a[0] 相当于&a[0][0] 的话, 就出现了这两种无法解释的问题。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-6-3 21:38:35 | 显示全部楼层
。。。没有批评,这个地方确实很多人没搞明白。说实在的,只是要用好C语言的话也没有必要把这个地方完全搞明白。如果要彻底明白的话,推荐大家去看下这个系列的文章http://blog.csdn.net/megaboy/article/details/482783
当年我也是看完这个系列的文章才彻底明白数组和指针的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-6-8 17:02:11 | 显示全部楼层
仰望天上的光 发表于 2012-6-3 21:38
。。。没有批评,这个地方确实很多人没搞明白。说实在的,只是要用好C语言的话也没有必要把这个地方完全搞明 ...

那篇文章,我看到数组名的时候,看不下去了。。。  {     
总之要牢牢记住,数组名是一个地址,一个符号地址常量,不是一个变量,更不是一个作为变量的指针!

        在数组名并非指针这个问题上,通常会产生两种疑问:
1。作为形参的数组,不是会被转换为指针吗?
2。如果形参是一个指针,数组名可以作为实参传递给那个指针,难道不是说明了数组名是一个指针吗?}   这段话就是那书上的。。。 说数组名是个常量,那 对于int a[10];  sizeof(a); 这样他如何给我解释?   &a ,如何给我解释?   常量能取地址吗?常量能求长度吗?  真扯淡。。。还有数组名能传参给一个指针, 跟
int a[10]; int * p=a;  有什么区别?  不就是给指针赋值吗? 还用他拉出来当作经典 讨论?    这文章对我i提出来的问题一个也解决不了。。。。。。。。版主大哥,你被误导了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-6-9 16:25:47 | 显示全部楼层
感觉还是不错的!我觉得这种东西还是自己理解好!嘻嘻!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2012-6-9 21:48:52 | 显示全部楼层
爱德华八世 发表于 2012-6-8 17:02
那篇文章,我看到数组名的时候,看不下去了。。。  {     
总之要牢牢记住,数组名是一个地址,一个符 ...

你认真看完并且理解了就不会存在那两个疑问了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-7-17 09:45:51 | 显示全部楼层
int a[10]; int * p=a;
这个为什么不好理解
int a;
double c=10.0;
a=c;//这个是可行的 如果你觉得警告不好看 那么
int b=10;
double d=b;//这个连警告都没有

有一些不同数据类型可以进行赋值的
怎么可以说 因为可以进行赋值 所以他们的数据类型就必然是一样
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2012-7-17 12:42:35 | 显示全部楼层
我是师兄 发表于 2012-7-17 09:45
int a[10]; int * p=a;
这个为什么不好理解
int a;

不错。。。也只有你说了句真话。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-9-14 22:21:14 | 显示全部楼层
学习一下~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-9-20 00:08:22 | 显示全部楼层
确实说的很全面。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-10-10 17:25:58 | 显示全部楼层
起码学习了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-12-5 15:33:04 | 显示全部楼层
和汇编寻址一个道理?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2012-12-24 13:40:25 | 显示全部楼层
顶啊大师啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2013-2-21 18:25:03 | 显示全部楼层
很不错的东西。。。支持下!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 07:56

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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