C语言基础四(指针)

来源:互联网 发布:网络评论文章怎么写 编辑:程序博客网 时间:2024/05/26 07:28

指针

指针表示一个地址,什么类型的指针就应该指向什么类型的内存空间,例如int *类型的指针就应该指向一个int类型的空间。

int a = 7;int *p = NULL; //指针的定义p = &a; //指针的绑定*p = 5; //指针的解引用

指针的运算

对于同类型指针p1,p2,一般有这几种运算p1+3, p1-3, p2-p1int a[5] = {1, 2, 3, 4, 5};int *p1 = a; //p1指向第一个元素int *p2 = p1 + 3; //p2 指向第4个元素int c = p2 - p1; //=3,表示相差3个指针所指向的类型的空间。

指针数组和数组指针

int *p[5]; //指针数组,因为[]优先级比价高,所以p表示一个数组,里面存放5int指针int (*p)[5]; //数组指针,p是一个指针,指向一个int[5]类型的空间
int **c;int a1[3] = {1, 2, 3}, a2[3] = {4, 5, 6};int b[2][3] = {a1, a2}; 等价于int b[2][3] = {1, 2, 3, 4, 5, 6};int (*p)[3] = b; //数组指针可以与二维数组匹配//*p 表示的是a1这个数组,*(p+1)表示a2这个数组。 **(p+1)表示的是a2中的第一个元素//这里的b和p在参与运算时,相当于二维指针,但是与 c 的类型是不同的,数组指针p指向int[3],c指向int *。 
char (*p)[10];char arr[][10] = {    "hello",    "world",};//p是一个数组指针,他可以与二维数组arr匹配。 //这里每行的字符数必须确定,行数可以不用注明,//因为在内存中存放时都是以一维数组的形式按顺序排放的,每行字符数的增减直接影响到下一行的位置,//所以要想存储下一行,必须先确定了上一行的存储大小。char arr1[][5][10];//三维数组也必须要确定第二维和第三维的大小,可以与char (*q)[5][10]匹配;

指针的强制类型转换

对指针进行强制类型转换一般是需要 目标指针类型的偏移量 ,或者需要 等号两边的指针类型 相互匹配。

char arr[] = "abcdefghijk";int *p = (int *)arr + 1;printf("%c %c %c %c\n", *(char *)p, *((char *)p+1), *((char *)p+2), *((char *)p+3));//输出为e f g h 
#define ADDR    0int *p = (int *)ADDR;

嵌入式是一种寄存器和内存统一编址的硬件设备,对寄存器读写操作时,可以直接对其地址进行操作。
假设地址是一个合法地址0x7FFF1234,这个地址的寄存器是32位寄存器,对这个寄存器读写操作

*(int *)0x7FFF1234 = 1;或者将其写成宏定义#define rG  *((volatile unsigned int *)0x7FFF1234)int a = rG;rG = 1;//volatile 关键字,表示经常改变的,编译器不会做优化,每次都是从内存中重新读取数据。

函数指针

函数名就是函数的首地址

int * f(int a, int b); //这是一个返回值为int *类型的函数;int (*f1)(int a); //函数指针,f1是一个指针,指向类型是int (*)(int )
int max(int a, int b){      return a > b ? a : b;  }  int main()  {    int (*f)(int, int); //定义了一个函数指针,指向‘返回值类型为int,有两个参数类型都是int’的函数      f = max; //函数指针f指向函数max,或者写成f = &max;      int c = f(1, 2); //或者写成c = (*f)(1, 2);     printf("%d \n", c);  

typedef

typedef int *   p_int1;#define p_int2  int * p_int1 a, b; //相当于int *a, *b;p_int2 c, d; //相当于int *a, b;
//定义一个函数类型,理论上应该是typedef (void (*)(int , int ))    FUNC1;但编译器编译不通过的,实际上应该写成typedef int (*FUNC2)(int , int );FUNC2是新类型名,代表了原类型int (*)(int , int )

typedef可以简化类型

typedef int (*FUNC)(int , int );int add(int a, int b){return a + b;}int sub(int a, int b){return a - b;}//定义一个返回值为FUNC类型的函数,返回值类型为int (*)(int , int )//int (*calculate(char operate))(int , int )//通过typedef可以简化成下面的定义。FUNC calculate(char operate){    switch(operate)    {        case '+':         return add;        case '-':        return sub;        dafault:        return NULL;    }}//最后还需定义一个用户调用的函数int cal(int a, int b, char operate){    FUNC fp = calculate(operate); //fp现在指向了加或者减的那个函数,或者指向NULL。    if(fp)        return fp(a, b);    else        return -1;}

malloc和calloc

申请的是堆内存。堆内存不会自己释放,直到整个进程运行完毕。
所以malloc( )申请的空间一定要保存好这段空间的首地址,用完之后free( )释放.

函数原型void *malloc(unsigned int num_bytes);//申请成功,返回这段空间的首地址,不成功返回NULL地址为NULL的空间在内核区域,所以在申请时,一定要判断是否申请成功当申请的字节数为0时,也会申请出一个最小单位的空间,这个空间用来保存申请空间的大小。也可以用free()释放。int *p = (int *)malloc(sizeof(int) * 5); //在堆内存申请5个int空间if(NULL == p){    printf("malloc error\n");    return 0;}memset(p, 0, sizeof(int) * 5); //给这段空间清零。//用完这段空间之后free(p); //指针p在使用时不能移动,否则释放不彻底,会内存泄漏p = NULL;//防止野指针乱指。

NULL

NULL是一种地址类型的0,(void *)0.
表示内存中最低端,也是就系统内核最开始的地方。

const

const int a = 1; //a在C和C++中存储的方式有所不同。

对于全局变量或者静态变量,C和C++中都是存储在数据段,也就是全局/静态存储区;
对于局部变量
C语言中,和普通局部变量一样也是存储在栈区,
C++中对const进行了优化,如果初始化为常量表达式,将其视为标识符常量,和宏定义类似,编译时直接替换,这叫常量折叠。
宏定义是在预编译阶段进行字符替换,替换结束后,就会丢弃原字符。
如果通过 别的变量的值 或者 地址中的值 初始化,就是不可折叠常量。

<常量折叠>(constant folding),编译的时候,任何用到 “a” 的地方,都会直接用常量表达式的值 “1” 去替换。
这时候a的值不需要访问存储空间来确定,程序中任何出现 a 的地方在编译期间就已经被替换,即使通过取地址来修改这个值,也是相当于改变了一个副本而已,取地址时,编译器会为a另外分配空间。

C++中const定义的变量是可以用于定义数组的元素个数。而C语言就没有这个优化特性,所以C语言的const修饰的变量是不能用来定义数组元素个数的。

const修饰指针

const int *a; //*a(a指向的空间)是const的int const *a; //同上int * const a; //地址a是const的int **const*a; //*a(a指向的空间,类型是int **)是const的,int *const**a; //**a(a指向的空间内容所指向的空间,类型是int *)是const的,可以理解为,const修饰它之后的内容,可以将他之后的内容看作是指针运算的表达式(表示修饰的空间)
原创粉丝点击