购物车0种商品
IC邮购网-IC电子元件采购商城
C语言指针相关问题
(2011/10/27 9:12:00)
一个有10个指针的数组,该指针是指向一个整型数的
int *p[10];
上面这个比较好理解,平时用得也比较多,问题是下面....


如果一个数组如下定义:
int a[10];
那么找个指针指向它只要int *p = a;就定义完成了...可以理解为“一个指向有10个整形数组的指针”
同样,有如下定义:
int (*p)[10];
该定义含义也是“一个指向有10个整型数数组的指针”,这个定义有点让我莫名其妙...写了那么多的C我还真没见过谁这么用的,因此想问个明白

请教高人指点...

网友评论:呵呵,

int A[10];
int (*p)[10];

p = A;

我测试恰恰是keil,vc,IAR通不过。


picc却能通过。

p = &A,
各种编译器总是没有问题。

网友评论:
int A[10];// 实际分配一个含10个int单元的数组
int (*p)[10];// 定义一个指针,注意尚未有实际空间被指定
同意上面差别。那么下面概念/写法一定是对的:[ ]左傍指针——[ ]左边必是指针,所以:
*P是指针,P[ ]是指针,A是指针,(*P)也是指针。所以:
*P=A ;——> P=&A; /P=A;// 概念上一样。既然编译结果唯一,自然2种写法都可以。

网友评论:感觉和函数指针类似

网友评论:有意思~~

网友评论:

谢谢大家的热心帮助!!
最近本人主要在搞一些钻牛角尖问题...主要因为有些前辈的程序实在太注重技巧,自己没点技巧就没法见招拆招~~
比如...有人偏偏就喜欢用下面这种语句:
(*(void(*)(void))0)();
还有的人风格是不错,就是...一个变量union套struct套来套去,1~6层这也没什么,10几层...这就有点什么了,比如A.B.C.D.E.F.G.H.I.J = 0;(把前面字母换成名字超长的类型)一个变量上百个字符,这真是非常雷人啊...
这个指针问题我基本弄懂怎么回事了...现在试着用自己的语言组织一下..
比如有这么个数组定义:
int a[10];
int *p;
p = a;
这个就是最常用的类型,随后*p便代表a[0],也可写成p[0],然后一旦执行了p++;之后,*p就代表a[1],p[1]等效为*(p+1)指的就是a[2]
如果扩展成二维数组,又假设有如下定义:
int b[10][10];
那么本质上是由10个一维数组组成,这10个数组的首地址为b[0]~b[9],这里的b代表的就是b[0]这个【首地址】的【地址】,现在有如下定义
int (*p)[10];
那么只要如此赋值:
p = &b[0];或者p = b;
那么(*(p + 1))[5];代表的就是b[1][5],这时候用p[1][5]来描述也是一回事..
又是同理,再次假设一个定义:
int c[10][10][10];
int (*p)[10][10];
int (*q)[10];
int *r;
如此赋值:p = &c[0];或者p = c;
那么(*(p + 5))[2][6]和c[5][2][6]等效
继续:q = &c[0][0]; 或者q = c[0];
那么(*(q + 12))[3]和c[1][2][3]等效
再来:r = &c[0][0][0];或者r = c[0][0];
那么*(r + 789)和c[7][8][9]等效......
这样的理解应该没问题了把?

网友评论:指针数组:即一个由若干指针构成的数组。
例:int *p[10] //定义了一个数组,该数组的元素为指向整型数据指针p。

数组指针:即一个指向数组的指针。
例:int (*p)[10] //定义了一个指针,该指针指向一个由十个元素组成的数组。

网友评论:我的keil通不过,有error恶

网友评论:我keil C51 编译通过.



网友评论:[]这个符号就是人强行规定的。 比较难以理解。只能死记硬背。

*这个符号是客观存在的。

API--------------控件 等价于 *-----------[]


个人观点

网友评论:struct搞个十几层很正常,编过复杂点的程序你就知道必要性了,不过人家不会A.B.C.D.E.F……这么用,
肯定函数也是一个套一个的,一层函数对应一层struct,数据则通过指针传递

网友评论:我一会用gcc试试.

各位前辈有讲讲为啥 p=A和p=&A一样啊. 这个真不知道. A作为一个地址, 也应该存在内存的, 有实体的, &A应该就是存放这个地址的内存地址啊. A==&A这个是咋回事? 难道指针变脸都在内存无实体???????



还有LS的"struct搞个十几层" 这个也太夸张了吧.........超大型数据库上这个量还有可能.

网友评论:个人看法:最重要的一点:A是常量指针!它的地址是一个常数。一个常数是包含在程序里的吧?例如:MOV A,#55H; 这个55H是跟着语句跑的吧,它有地址特征吗?它需要间接寻址吗?

网友评论:int *p[10];
和int (*p)[10]
定义不同。
最大的区别应该是在做指针的加法时就很明显吧。即p++;
如果是 int *p[10]; 则p++,p会增加2
如果是 int (*p)[10],则p++,p会增加20;
呵呵,我觉得应该是这样吧。主要是告诉编译器指针的类型。

网友评论:

这么热闹啊!我前段时间也用了这个数组,不玩虚的,直接举例。
unsigned charu8_sample1[3]={1,2,3};
unsigned char u8_sample2[3]={3,2,1};
unsigned char *p_u8_sampleX[2]={u8_sample1,u8_sample2};
于是
*p_u8_sampleX[0] = u8_sample1[0];


unsigned char u8_sampleXY[2][3]={{1,2,3}{3,2,1}};
unsigned char(*p)[3] = u8_sampleXY;
*p_u8_sampleXY[0]= u8_sampleXY[0][0]=1;
*(p_u8_sampleXY+1)[2]= u8_sampleXY[1][2]=1;
*(*(p_u8_sampleXY+1)+1)= u8_sampleXY[1][1]=2;

网友评论:
*p_u8_sampleXY[0]= u8_sampleXY[0][0]=1;
*(p_u8_sampleXY+1)[2]= u8_sampleXY[1][2]=1;
*(*(p_u8_sampleXY+1)+1)= u8_sampleXY[1][1]=2;
写清楚呀:
*u8_sampleXY[0]= u8_sampleXY[0][0]=1;
*(u8_sampleXY+1)[2]= u8_sampleXY[1][2]=1;
*(*(u8_sampleXY+1)+1)= u8_sampleXY[1][1]=2;

网友评论:36#

对地址进行取地址 等于地址本身keil下。

设地址为ADDRESS

那么ADDRESS = &&&&&&&&&&&&&&&&&&&&ADDRESS。

这就是编译器编写的人随便弄的。

网友评论:gcc 测试结果如下:
程序1:
    int main(void)
    {
    int A[10];
    int (*p)[10];
    p = A;
    (*p)[1] = 1;
    (*p)[2] = 2;
    return 0;
    }
复制代码$ gcc -o test test.c -Wall
test.c: In function ‘main’:
test.c:5: warning: assignment from incompatible pointer type
能编译成功, 正常运行,但有W。

程序2,
    int main(void)
    {
    int A[10];
    int (*p)[10];
    p = &A;
    (*p)[1] = 1;
    (*p)[2] = 2;
    return 0;
    }
复制代码$ gcc -o test test.c -Wall
无任何警告成功。

网友评论:那么经我测试, 这个

p==&p
&p==&&p
&&p==&&&p

确实成立,


这个不知道是什么原因。

恐怕不是 “这就是编译器编写的人随便弄的“这么简单吧。

简单的现象总有背后的解释。哪位大侠能解释下。我google了下没有查到端倪。

网友评论:数组名在C中,有的时候可以认为它就是代表着数组首地址。

这还要做什么解释?

网友评论:
定义一个数组int A[10],A是一个常量,类型是int *,一个常量前加“&”并不是对该常量取地址。&A也是一个常量,和并且“A”在数值上是相同的,但"&A"的类型是int (*)[10],所以在42楼的第一种写**有警告。
同理,如果定义一个二维数组int B[1][10],那么B[0]是常量,类型是int *,&B[0]也是常量并且在数值上与B[0]相同,但类型是int (*)[10]。

网友评论:
定义一个数组int A[10],A是一个常量,类型是int *,一个常量前加“&”并不是对该常量取地址。&A也是一个常量,和并且“A”在数值上是相同的,但"&A"的类型是int (*)[10],所以在42楼的第一种写**有警告。
...
ShakaLeo 发表于 2010-2-27 14:55 A确实是个常量, 但这个常量我认为在内存也是有空间存它的, 就是它也要被放在一个内存地址里, 那么, 为什么&A不是存放A的地址呢? 非要和A相等干嘛? &不是取地址符号么.

比如: A的值为0x0003 地址为0x456366那么, &A应该是0x456366啊.

恩, 那&&A又是怎么回事呢? 这个难道是: A的值没有加载到data区, 不可能啊, A的值是系统现分配的应该................





哪位大侠能详细的说下这个问题

网友评论:[]的优先级比*高

讨论的挺多,没细看,LZ的意思应该是纠缠于此吧

网友评论:
A确实是个常量, 但这个常量我认为在内存也是有空间存它的, 就是它也要被放在一个内存地址里, 那么, 为什么&A不是存放A的地址呢? 非要和A相等干嘛? &不是取地址符号么.

比如: A的值为0x0003 地址为0x456366那么, &A ...
sinanjj 发表于 2010-2-27 23:41
A的值既不在data区,而且和“常变量(即const型变量)”不同,也不在const区,A的值可能在code区,也可能根本没有一个固定的位置来存储A的值。所以&符号不是取地址。下边是IAR EWARM邮购EWARM环境下"p=&A"的汇编指令:
LDRR0, [PC, #+808] ;把变量p的地址加载到R0
LDRR1, [PC, #+800] ;把A的值加载到R1
STRR1, [R0, #0] ;把A的值存储到变量p的地址上

PC+808和PC+800这些位置都是在code区的。所以“存储变量p的地址”的位置和“存储A的值”的位置都是在code区的。

ARM没有直接寻址的指令,所以只能把这些值存储在code区的某个位置来间接寻址。对于有直接寻址的MCU来说,甚至没有存储A的值的位置,比如AVR,同样是p=&A, ICCAVR的汇编指令如下:
LDI R24,0x04
LDI R25,0x01 ;数组A的首地址是0x0104,把A的值加载到R24和R25
STS0x0103,R24
STS0x0102,R25 ;指针p的地址是0x0102,把数组A的首地址直接存储到变量p的地址上

可以说A的值是在代码中,没有一个固定的存储位置,所以这时候对A取地址就更没有意义了,所以&A不会是对常量A取地址。
对于&&A的写法,我在上面的两个编译器里都试了一下,都会报错,估计不是标准用法。

网友评论:
A的值既不在data区,而且和“常变量(即const型变量)”不同,也不在const区,A的值可能在code区,也可能根本没有一个固定的位置来存储A的值。所以&符号不是取地址。下边是IAR EWARM环境下"p=&A"的汇编指令:
LDR ...
ShakaLeo 发表于 2010-2-28 08:42
有幸得到骨灰级大侠指点, 实乃万幸。

那么, 从汇编代码上看, 也就是说:A指代的地址值在编译的时候已经确定,并写入code区,不在程序运行中改变了。所以对A取地址无意义。

从这个解释上看, 争论中, HWM前辈实际对C的理解更胜一筹啊。呵呵。

p=&A; 符合语法解释但不符合实际模型。
p=A; 符合实际模型但语法上说不过去。



再次感谢您的解释。

网友评论:指针基础啊
int (*p)[10]指向一个匿名数组呀

网友评论:又见申明问题。
p1 = &A; p2 = A; 中 A 是数组名, 可以被编译器当作常数对待, 但数组名就是数组名, 不是概念的常数. p1 = &A; p2 = A 或许最终在汇编层面都被编译器作为常数处理,但在编译器层面有类型的不同。 &A 不是对常数取地址,而是对数组名取地址,即得到一个指向数组的指针。 而 p2 = A, p2 只是指向数组第一个元素的指针, 不是指向整个数组. 这种区别体现在指针操作上:
p1++; p2++; 此时, p1, p2 指向了不同的地址。

int a1= ((int) (p1+1)) - ((int) p1);
int a2= ((int) (p2+1)) - ((int) p2); 注意 a1, a2 的不同。

另外: 这种申明问题,用我以前讲过的一个中心,两个基本点来解题, 就很简单。 int (*p)[10] 的中心是 *p (因为括号的优先级), 说明p是一个指针。 于是整个申明就是 p 是一个什么什么的 指针。

网友评论:10#

char *P[10];——>char P[ ][10];// 二维数组就是个指针数组。字符串数组中很常用的写法。

兄弟这个...char *p[10] ,是不是声明了一个10个元素的指针数组呢?如果是二维数组表示的话 是不是char P[10][]呢?

网友评论:呵呵,凑个热闹.
单从C语言的角度的讲,涉及到某个具体的编译器时,那要看它对C标准支持到什么程度.
有那种比较古老的C编译器,对指针的处理是宽松的.
如果是符合C99标准的现代编译器,对指针的处理是"强类型"的,不允许不同类型的指针直接赋值(void* 不在讨论范围).
当然你可以强行关闭"强类型"检查.
这里我只讨论那种"强类型"的C.
这种C语言,强烈区分"数组"和"指针",虽然,数组的名字可以做为它第一个值的地址来用,
但这仍然是2个不同的类型.这个因为在C中使用过于频繁,特别豁免的("ARM"一书,提起过这个,好像)
int * p1 [10];
int (* p2) [10];

这是2个不同的类型.
从C语言的运算符优先级看.
int * p1 [10];
------- p1 是一个数组
--------- 数组的内容由指针组成
------------- 指针所指的对象类型是 int
p1是一个有10个int *组成的数组, 即p1的类型是 int *

int (* p2) [10];
------ p2 是一个指针
----------- 指针所指对象是一个10个对象所组成数组
--------------- 数组对象的类型是int
p2 是一个指向10个int所组成的对象的指针. 即 p2 的类型是 (int[10])*


int i[10]; // i 是一个10个int所组成的数组
// i 也可以表示 i[0] 的地址, 即 &i[0]
p1 = i; //错: p1 是数组
p1[0] = i;//OK: p1[0]的类型是int*, i是i[0]的地址,也是int*

p2 = i; // 错: p2 的类型 (int[10])*, 而i是int[10],即使看作int*,也同p2的类型不同
p2=&i; // OK: p2 的类型 (int[10])*, 而i是int[10], &i(取址),类型当然是(int[10])*

网友评论:
定义一个数组int A[10],A是一个常量,类型是int *,一个常量前加“&”并不是对该常量取地址。&A也是一个常量,和并且“A”在数值上是相同的,但"&A"的类型是int (*)[10],所以在42楼的第一种写**有警告。
...
ShakaLeo 发表于 2010-2-27 14:55 再饶舌下:

int A[10];
A除了可以表示数组的首地址外(此时它的类型是是int *),
同时它还是个对象,类型是int[10];
所以是可以对它取址的,即&A是可以的.
同时,因为A的地址同A[0]的地址是相同的(因为它是数组嘛),所以下面的程序片段是正确的:
void * p1= A; // p1 = &A[0];
vod * p2 = &A; // p2 = &A;
ASSERT(p1==p2);// 此断言是成立的

网友评论:
再饶舌下:

int A[10];
A除了可以表示数组的首地址外(此时它的类型是是int *),
同时它还是个对象,类型是int[10];
所以是可以对它取址的,即&A是可以的.
同时,因为A的地址同A[0]的地址是相同的(因为它是数组嘛),所以 ...
lenglx 发表于 2010-3-4 18:47
我并不是说&A这个表达式有问题,而是说&号在这里不是对A这个常量取地址的意思,你可以看看sinanjj在36楼的发言,再看看我在48楼的分析,A是一个常量,很有可能只出现在指令的操作数中,这样就没有一个固定的存储地址,何来取地址?

网友评论:mark

网友评论:哈!再饶舌一下。A不能叫常量,——A叫做“指针常量。”
指针是一个地址。所以一个指针,只能作为“左值”使用。例如:
A=&A[0]; //正确写法

所以下面写法有语法问题:
P=A; //地址A 成了右值。
但实际中为什么可以这么写?HWM 讲过了。编译器认为没问题。它有它的道理。

P=A;和P=&A;编译结果一样。
把警告级别降低就不会出现警告提示了。

网友评论:P=&A;
所有编译器都可以无警告通过编译。

P=A;
少部分编译器可以通过,但有告警。
大部分编译器不可以编译通过。

网友评论:顶 53 楼 lenglx “强类型“。
57楼冷漠概念不清.

数组就是数组, 不可以与常量混淆. 某些 compiler(往往无os内存管理器) 编译连接时静态分配内存,因而数组地址在编译时可以作为常量嵌入, 连接时确定, 此时,可以认为数组名 A 是常数。另外一些compiler, 无法在编译时确定地址, 只能在运行时由 os 的内存管理器分配后,根据 offset 确定。

"P=A;和P=&A;编译结果一样。", 但概念不一样。 就如同:
int** p1 = (int**) 1234;
int* p2=(int*) 1234;

int (*p1)[10]; 的定义本身说明了 p1 是一个“强“类型, 那么还是严格遵照类型去做。

网友评论:1#
我大概看了一下Intp[10], int *p[10], int (*p)[10]
简单的说:
第一个定义了10个整型数据;
第二个定义了10个指针且每个指针都必须指向INT数据;
第三个定义了1个指针且这个指针只能指向INTa[10]的数组
不过在引用时,还有点不会写。望大侠们修改了。

网友评论:之前一直很糊涂&符号加与不加的区别,以及多维数组地址问题,多亏53楼lenglx大侠的讲解使我茅塞顿开...

网友评论:我最讨厌用指针了

网友评论:int a[10];int*p=a;首先a就是一个指针,a是一个指向数组首个元素的指针,该元素的类型是整形,那么p也就和a一样了,p是一个指向类型为整形数据的指针;
int (*p)[10];首先*p就是一个拥有10个整形数据的数组(例如:将*p用a代替,a[10]很显然是数组),那么p就是一个指向数组的指针,组成该数组的元素是10个整形数据。
不知道这样了理解对不?欢迎大家拍砖。

网友评论:11楼的这句“ p = A;// 获得数组内存空间”好像编译通不过吧?
p是一个指向类型为数组的指针,而A是一个指向类型为整形数据的指针,类型的不一样能赋值过去吗?
要赋值也起码需要转换下吧?
typedef int (*ap)[10]
int A[10];
int (*p)[10];
p=(ap)A;
不知道说的对不?欢迎大家拍砖。

网友评论:只知道这么用:
int a;
int *P;
p=&a;
*P==a;
别的什么方法没有试过,怕出问题,稳定最要紧

网友评论:看看《C语言核心编程》和《C和指针》

网友评论:路过

网友评论:《C和指针》

网友评论:学习!

浏览:(1010)| 评论( 0 )
博文评论

  • 昵 称:
  • 内 容:10~250个字符
  • 验证码: 验证码看不清楚?请点击刷新验证码
  •                      
  • 博文分类

    热点博文

    最新博文

    最新评论

    IC电子元件查询
    IC邮购网电子元件品质保障