小结 | 指针、数组和指针@_@
来源:互联网 发布:linux重启命令 编辑:程序博客网 时间:2024/06/05 23:59
一、指针
一级指针
我们通常说到指针的时候,指的就是一级指针。
1、提几点指针中容易混淆、不易分辨的知识点:
- 声明的时候
int *p;
int * 指的是类型名,此时的*p
指的是这个 p 是指针类型,int
再进一步说明p是整型的指针变量。当我们在调用的时候,p
是指针变量,p = a;
p指向变量 a 的空间;*p = 10;
此时的*
表示解引用,即*p
代表 p 指针所指向的空间中的内容——10。 - 指针就是地址。
a = sizeof()
中放一个地址,32位平台 a = 4 byte;64位平台 a = 8 byte。因为32位平台有32根地址线,刚好对应 32 bit = 4 byte。- 一个字节的内存配置一个地址,声明的时候分为:
int *、 char*、double*
指的是指针可以向后访问的字节权限,int* 可以向后访问 4 byte。 void *p;
是一个没有定义类型的指针变量,他可以接收任何类型的指针,但是在使用的时候必须强转,如果没有类型转换的话,没法进行指向和解引用。如:void* memcpy(void *dest, const void *src, int count); (int *)dest ++;
2、指针的出现就是为了访问内存的时候更加灵活和方便。
下面例子说明的是给指针配置不同类型的影响:
#include <stdio.h>#include <stdlib.h>int main(){ int a = 0x11111111;//十六进制整型 int* pi = &a; char* pc = &a;//此处会警报类型不对,但是我们依然可以操作。//指针定义的时候需要另外申请一块内存,在申请的内存中存放着目标的地址 printf("&a = %p\n", &a); printf("&pi = %p\n", &pi); printf("&pc = %p\n", &pc);//不同类型的指针,进行+1移动的时候,移动的字节数不同 printf("pi + 1 = %p\n", pi + 1); printf("pc + 1 = %p\n", pc + 1);//不同类型的指针,向后获取的字节不一样,int 型 4 byte,char 型 1 byte printf("*a = %d\n", a); printf("*pi = %d\n", *pi); printf("*pc = %d\n", *pc); system("pause"); return 0;}
二级指针
1、二级指针是指向一级指针的指针,它用来存放一级指针的地址。
int a = 10;int* pa = &a;int* *ppa = &p;
2、本质和一级指针没有大的差别,下面利用 const 修饰指针,进一步理解二级指针。
#include <stdio.h>#include <stdlib.h>int main(){ int a = 10; int b = 20; int* pa = &a; int* pb = &b; //1 const int**pp = &pa;//不可修改的整型数据 pp = &pb;//可以修改指向 //**pp = 30;//不可修改的整型数据 //2 int** const pp = &pa;//不可修改的二级指针 //pp = &pb;//不可修改指向 //3 int* const *pp = &pa;//不可修改的一级指针的值 pp = &pb;//可以修改指向 //*pp = pb;//不可以修改值 printf("%d\n", &a); printf("%d\n", &b); printf("%d\n", pa); printf("%d\n", *pa); printf("%d\n", &pa); printf("%d\n", pb); printf("%d\n", *pb); printf("%d\n", &pb); printf("%d\n", pp); printf("%d\n", *pp); printf("%d\n", &pp); int a = 10; int b = 20; //1 const int *p = &a;//不可修改的一级指针 //*p = 30;//整型数据未修改成功 p = &b;//可以修改指向 printf("%d\n", a); printf("%d\n", *p); //2 int* const p = &a;//不可修改的整型数据 *p = 30;//可以修改值 //p = &b;//不可以修改指向 printf("%d\n", a); printf("%d\n", *p); system("pause"); return 0;}
二、指针数组
指针数组是一个数组,它的每一个元素是指针
int *arr1[10];char **arr2[10];
上面的例子中,因为 [] 的优先级比 * 优先级高,所以它先是一个数组,然后元素的类型是指针
int a = 10;int b = 20;int* arr[2] = {&a, &b}; //&a,&b 的类型是 int * 。
char* arr[3] = {"asdf","qwer","zxzx"};printf("%d\n",sizeof(arr)); //12 三个字符型地址printf("%d\n",strlen(arr)); //x 未知值,数组中没有'\0',所以strlen()找不到结束字符
三、数组指针
数组指针是一个指针,它指向的元素是数组。
int (*p)[10];
p先和 * 结合,先是一个指针,然后与 [] 结合,指向类型是数组。它的类型是int (*)[10]
。
int arr[10] = {0};int (*p)[10] = &arr; //用于存放数组的地址char* arr[10];char*(*p)[10] = &arr;int(*p[5])[3];
四、指针和数组的关系
1、数组的小结,请点击:小结 | 一维数组、二维数组。
2、在引用字符串的时候,可以用数组或者指针来定义:
char arr[] = "abcdef";char *p = "abcdef";
两者是有区别的,用数组定义的字符串可以修改,因为它存放在栈中。但是用指针定义的字符串是不可以修改,因为它存放在常量区,是字符串常量。
3、在调用函数是,形参如果利用了数组或者指针,其中有一些这样的转换关系:
//1 一维数组传参void test(int arr[]);void test(int arr[10]);//arr[10] 参数数量 10 根本没有影响,因为声明和定义的时候,只关心形参类型。void test(int *arr);void test(int *arr[20]);//正确void test(int **arr); //正确 传递的是首元素的地址,首元素的类型是int* 首元素的地址是 int**int main(){ int arr[10] = {0}; //整型数组 int *arr2[20] = {0}; //整型指针数组 test(arr); test2(arr2);}//2 二维数组传参void test(int arr[3][5]);//void test(int arr[][]); //错误的传参,二维数组一定要知道每一行有几列void test(int arr[][5]);void test(int* arr[5]); //错误,传递的是第一行的地址,第一行是数组,所以要用数组指针来接收void test(int (*arr)[5]); //正确的传参,传过来的是二维数组的第一行的地址,用一维数组指针来接收,类型符合void test(int **arr); //错误,同 int* arr[5] int main(){int arr[3][5] = {0};test(arr);}
五、函数指针
函数指针,指向函数地址的指针。
如何获取函数的地址,如何调用函数:
void test(){ printf("\n");}int main(){//加不加 & 均可以获得函数的地址 printf("%p\n",&test); printf("%p\n",test);//以下四种调用情况都一样,* 符号在这里只是摆设,没有什么价值 (&test)(); test(); (*test)(); (**test)(); return 0;}
char test(const char* str){ printf("%s\n",str);}int main(){ char (*p)(const char*); //函数指针,其类型为:char (*)(const char *) p = &test; //用来接收函数的地址 p("asdf"); //可以输出 asdf}
六、操碎心的代码
来自《C 陷阱与缺陷》
1、(*(void(*)())0)();
整体是一个函数调用,(void()()) 是强转,将 0 的类型强转为函数指针,获得0地址, 解引用,获得0的内容。即调用了 0 地址处的函数。
2、void(*signal(int, void(*)(int)))(int);
令 signal(int, void(*)(int)) = a
,则void(* a)(int)
。函数是 signal,第一个参数是 int 第二个参数是 void(*)(int)
,它的类型是函数指针。除去这个函数,即除去 a ,剩下的是函数返回类型 void(*)(int)
,也是函数指针。
七、感想
晚安,各位大佬。
好晕乎
- 小结 | 指针、数组和指针@_@
- 数组和指针小结
- 指针和数组小结
- 20170911_指针数组和数组指针的区别
- 指针和指针数组
- 数组与指针小结
- 数组、指针、引用小结
- 41_指针数组
- 指针与数组_数组指针
- 指针数组和数组指针
- 指针数组和数组指针
- 指针数组和数组指针
- 指针数组和数组指针
- 数组指针和指针数组
- 指针数组和数组指针
- 数组指针和指针数组
- 指针数组和数组指针
- 指针数组和数组指针
- 进程间通信---Socket
- C++ Windows Server 2016上修改注册表IIS10.0降级安装PHPManager
- Nginx 动静分离(代理Tomcat,Jetty)
- Python基础(3)——北京市地铁买票问题(思维练习题)
- xshell远程连接Ubuntu配置
- 小结 | 指针、数组和指针@_@
- JavaScript-数组的方法
- 两个文件的相对路径
- UCOSii任务就绪表之OSUnMapTbl[16*16]的数组是如何得到的
- hdu 6060 RXD and dividing (贪心)
- Tensorflow学习笔记(4)-mnist(MultilayerConvolutionalNetwork)
- Linux /etc/passwd文件的分析
- GCC4.8源码安装
- Log4j使用配置记录