<2012 10 29> 调C记录 <有关指针 数组 声明>
2012-11-04 17:22
375 查看
<调C记录 2012 10 29>
1、指针的定义与解用
(1)如果需要解用一个指针,那么首先需要定义一个指针。首先,我们对于一般的变量指针,可以按普通方式定义
如: char *ptr
prt是一个指向char数据的指针,它本身是一个存放在某个内存地址中(编译器分配)的变量,这个变量的内容也是一个地址,该地址指向的内存空间存放着一个char型数据。
可以这样解用并赋值:*ptr = 255
但是不能解用没有被定义的空间,比如 *(ptr+1),编译能通过,但是运行时会报错。
(2)如果先定义一个数组如 char a[10] ,将该数组的地址赋予指针ptr,则可以用解用指针的方式引用数组。这经常用在调用函数传递数组变量时,当然用malloc函数申请的堆内存空间也可以用解用指针的方式进行引用。
如
(3)注意上面程序的最后一行,为什么需要两个“*”号来解用呢? 是因为数组a和指针ptr不同,指针ptr是一个变量,虽然它存储的数据就是数组a的首地址,但它本身也需要存储空间,这样的变量才能被*解用并引用。我们不能直接用*(a+9)来解用这个数组首地址offset9个char的内存,是因为a本身不是一个变量,而是一个常量。需要先用(char *)(a+9)强制转换(或者叫做匿名定义)一个指针变量,然后再解用。所以左起第一个*是解用,第二个*是定义指针变量。
在底层编程操作功能部件的寄存器时,可能用到这样的定义方式,如:
这个寄存器WTCON的内存映射地址是0x53000000,该语句的含义就是先定义一个指向unsigned long的匿名指针,该指针中存放的地址是0x53000000,然后对该指针解用。这样给WTCON赋值就相当于给那个寄存器赋值。
2、关于数组的引用
定义一个数组char a[10],引用从a[0] ... a[9]共10个char。
上面说过对于数组 char a[10],a 和 &a 都表示这个数组首地址(第一个元素的地址),他们是常量。但是编译器对于他们的运算是不同的!
(a+1)表示数组下一个元素的地址,(&a+1)表示内存中连续的第二个这样的数组对象开始的元素的地址(如果没有定义,则该地址内的数据随机),即(&a+1) = (a+10)。
编译器是逻辑的,它认为a只是指向一个char,而&a指向整个数组,因此在加减运算时也依照这样的含义。
3、一个复杂声明
这是linux内核代码中一个注册信号量的声明
|-- P1=void(*func)(int)
| func是一个函数指针,参数int,返回void
|-- void ( *signal(int signo, P1) ) (int)
| signal是一个函数,参数int signo和P1,返回一个函数指针。
| 该返回的函数指针指向的函数f()的参数是int,返回void
### 定义一个返回函数指针、参数为ZZZ的函数,该函数指针指向的函数参数是XXX,返回值是YYY
---> YYY (*fun(ZZZ))(XXX)
调用时,fun(ZZZ)返回一个函数指针,然后用*对其解用。
1、指针的定义与解用
(1)如果需要解用一个指针,那么首先需要定义一个指针。首先,我们对于一般的变量指针,可以按普通方式定义
如: char *ptr
prt是一个指向char数据的指针,它本身是一个存放在某个内存地址中(编译器分配)的变量,这个变量的内容也是一个地址,该地址指向的内存空间存放着一个char型数据。
可以这样解用并赋值:*ptr = 255
但是不能解用没有被定义的空间,比如 *(ptr+1),编译能通过,但是运行时会报错。
(2)如果先定义一个数组如 char a[10] ,将该数组的地址赋予指针ptr,则可以用解用指针的方式引用数组。这经常用在调用函数传递数组变量时,当然用malloc函数申请的堆内存空间也可以用解用指针的方式进行引用。
如
char a[10]; char *ptr; ptr = a ; //或者这里用 ptr = &a也是可以的,因为a = &a都表示数组首地址 *(ptr+9) = 255; a[9] = 244; *(char *)(a+9) = 243;
(3)注意上面程序的最后一行,为什么需要两个“*”号来解用呢? 是因为数组a和指针ptr不同,指针ptr是一个变量,虽然它存储的数据就是数组a的首地址,但它本身也需要存储空间,这样的变量才能被*解用并引用。我们不能直接用*(a+9)来解用这个数组首地址offset9个char的内存,是因为a本身不是一个变量,而是一个常量。需要先用(char *)(a+9)强制转换(或者叫做匿名定义)一个指针变量,然后再解用。所以左起第一个*是解用,第二个*是定义指针变量。
在底层编程操作功能部件的寄存器时,可能用到这样的定义方式,如:
#define WTCON (*(volatile unsigned long *)0x53000000)
这个寄存器WTCON的内存映射地址是0x53000000,该语句的含义就是先定义一个指向unsigned long的匿名指针,该指针中存放的地址是0x53000000,然后对该指针解用。这样给WTCON赋值就相当于给那个寄存器赋值。
2、关于数组的引用
定义一个数组char a[10],引用从a[0] ... a[9]共10个char。
上面说过对于数组 char a[10],a 和 &a 都表示这个数组首地址(第一个元素的地址),他们是常量。但是编译器对于他们的运算是不同的!
(a+1)表示数组下一个元素的地址,(&a+1)表示内存中连续的第二个这样的数组对象开始的元素的地址(如果没有定义,则该地址内的数据随机),即(&a+1) = (a+10)。
编译器是逻辑的,它认为a只是指向一个char,而&a指向整个数组,因此在加减运算时也依照这样的含义。
3、一个复杂声明
void ( *signal(int signo,void(*func)(int)) ) (int)
这是linux内核代码中一个注册信号量的声明
|-- P1=void(*func)(int)
| func是一个函数指针,参数int,返回void
|-- void ( *signal(int signo, P1) ) (int)
| signal是一个函数,参数int signo和P1,返回一个函数指针。
| 该返回的函数指针指向的函数f()的参数是int,返回void
### 定义一个返回函数指针、参数为ZZZ的函数,该函数指针指向的函数参数是XXX,返回值是YYY
---> YYY (*fun(ZZZ))(XXX)
调用时,fun(ZZZ)返回一个函数指针,然后用*对其解用。
相关文章推荐
- <2012 11 6> 调C记录 <int main(int argc,char **argv)中的“char **argv”怎么理解?>
- <2012 10 28> 调C记录 <编译与链接相关>
- <FORM action=reg.asp?action=apply method=post> <INPUT type=submit value="请认真查看<服务条款和声明>(10
- <深入理解C指针>学习笔记和总结 第四章 指针和数组
- <<算法竞赛入门经典>> 习题2-10
- <<学习VI和VIM编辑器>>读书记录<4>
- 数组<->指针<->动态数组之间的关系
- <Java>Java数组的声明与初始化
- <C基础>数组和指针
- <<C语言深度剖析>>学习笔记之五:指针与数组
- 【Foundation-10-4】#import <Foundation/NSArray.h>可变数组,一般
- 9.12学习记录<<C和指针>>读后感
- 数组与指针<二>
- 数组<->指针<->动态数组之间的关系
- <<人工智能及其演化>>随手记录
- <ZZ>linux shell 数组有关的一些知识
- <<Effective C++>>读书笔记4: 设计与声明
- <2012 10 06> FL2440开发板的U-boot-2010.09版本移植 ____ U-boot中常用参数设定及常用宏(u-boot环境变量、USB、内核引导)
- 位运算符 | << >> & ^ ~的厉害__10进制 To 2进制
- <s:iterator>标签遍历动态数组<泛型>:ArrayList<对象>,怎样批量修改数据并一起提交到后台