使用指针访问数组 创建一个数组int arr[10]={0} ,一般我们访问数组是用下标引用操作符如arr[5],。 用指针变量来接收。 但是在日常中我们能看到用 int arr[]去收arr,让我们误认为是传了整个数组。 但其实这只是为了一些新手更好理解所以才这样子表示。 这是个固定格式,其中[]里面也可以写操作数(数组的元素个数) 所以一维数组传参,形参部分可以写成数组形式,也可以写成指针形式。但其本质都一样。 冒泡排序 冒泡排序是通过两两比较从而进行排序。 假设数组有十个整形元素,10,9,8,7,6,5,4,3,2,1.将其从小按大排序。 两两比较则要比较九次则能得出最大的数。得出最大的数的过程叫一躺冒泡排序。所以我们需要进行九躺冒泡排序才能排序好。
函数指针数组 函数指针数组是一个用来存放函数指针(地址)的数组。 如上图,是将两个函数指针存入数组中。如何写函数指针数组名呢? 我们可以先写出函数指针类型int (*)(int,int)然后在(*)里面加上数组名[]即可。 指向函数指针数组的指针 如何写指向函数指针数组的指针呢? 如果你把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。 如果返回值小于0(<0),那么e1所指向的元素会被排在e2所指向元素的前面。 如果返回值大于0(>0),那么e1所指向的元素会被排在e2所指向元素的后面。 如果返回值等于0(=0),那么e1所指向的元素和e2所指向的元素顺序不确定。
2.使用指针访问数组 既然arr是数组的首元素的地址,那么它赋值给p时,其实可以认为p等价于arr。所以arr[i]也就等价于p[i]。 sz1是整个数组元素的个数(因为它是直接打印主函数中的数组元素个数); 而sz2是函数中的数组元素的个数,但这里其实取的只是首元素,也就只有一个了。 函数形参的部分是使用指针变量来接收首元素的地址。 既然二级指针是指向指针的指针,那么肯定就有指向二级指针的指针,被称为三级指针,还有四级指针五级指针...它们都被统称为多级指针。 6.指针数组与数组指针 指针数组是元素是指针的一类数组,它的本质是数组。 数组指针是指向某个数组的指针,它的本质是指针。 7.指针数组与普通数组的联系 1. 数据类型不同 普通数组的数据类型是普通的类型,但指针数组的数据类型实际上是普通的类型再加上*号,用来表明该数据是指针。 2.
如果我们想写一个加法函数,然后我们把这个函数的地址存放到pf1里面去,再写一个减法函数,将这个函数的地址存放到pf2里面去,但是我们如果写更多同类型的函数,都这样存放地址的话,就要重复这样的操作,所以我们可以创建一个函数指针数组 (int,int) = ⋐ int (*pfarr[2])(int,int)={&Add,&Sub}; return 0; } 函数指针数组的用途:转移表. 指向函数指针数组的指针 指向函数指针数组的指针是一个 指针 指针指向一个 数组 ,数组的元素都是 函数指针 ; 如何定义? //函数指针-cmp指向了一个函数,这个函数是用来比较两个元素的 //e1和e2中存放的是需要比较的两个元素的地址 ); 如果我们需要排序整型数组的话,我们就要自己写一个比较函数 写成void*指针的好处是在进行调用这个函数的时候可以根据自己的需求进行转换。 所以我们需要将e1和e2进行强制类型转换成int*,将他们做差,将结果返回。
函数指针数组 之前我们已经学习过指针数组,比如整型指针数组等,因此我们可以以此进行类比: int Add(int x, int y) { return x + y; } int Sub(int x, 指向函数指针数组的指针 指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素都是函数指针。 回调函数 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。 - 这个函数指针指向的函数,能够比较base指向数组中的两个元素 ); 这里先对 void* 进行一个解释: //void* 的指针 - 无具体类型的指针 //void* 类型的指针可以接收任意类型的地址 其次,对于不同类型的数据,不能简单地使用 > 比较,所以我们要在参数部分加上函数指针cmp,将实现2个元素比较的这一个函数的地址,以参数的形式传递过来。
指针详解(2) 对数组名的理解 在C语言里数组名还表示着数组首元素地址。 int arr[5] = {1, 2, 3, 4, 5}; int* p = &arr[0]; int* p = arr; 以上这两种,对指针p进行赋值的操作均是等价的,都将数组首元素的地址赋给指针p。 不妨,我们可以测试一下 int main() { int arr[5] = {1, 2, 3, 4, 5}; printf(" &arr[0] = %p\n", &arr[0]); printf( 由于传递的是地址,在函数里可以使用指针变量来接收 void test(int* arr) { //printf("arr[2] = %d", arr[2]); printf("*(arr + 1)= 初始化: int a = 10; int b = 6; int* parr[2] = {&a, &b}; int* p[5] = { 0 }; 使用指针数组,它与常见的整形数组用法区别不大 printf
指针和数组 指针变量:指针变量就是指针变量,不是数组,指针变量的大小是4/8个字节,专门是用来存放地址的。 #include <stdio.h> int main() { int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int i = 0; int 二级指针 指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里? 这就是二级指针。 = "cuihua"; //指针数组 char* parr[] = { arr1, arr2, arr3 }; int i = 0; for (i = 0; i < 3; i++) { 3, 4, 5 }; int arr2[] = { 2, 3, 4, 5, 6 }; int arr3[] = { 3, 4, 5, 6, 7 }; //指针数组 int* parr[] =
1.指针初始化; 2.小心指针越界 3.指针指向空间释放即使置NULL 4.指针使用之前检查有效性 #include<stdio.h> int main(void) { //当前不知道p应该初始化为什么地址的时候 指针-指针 //指针-指针 #include<stdio.h> int main(void) { int arr[10]={1,2,3,4,5,6,7,8,9,10}; printf printf("%d\n",2[arr]); //代码运行结果是3 printf("%d\n",arr[2]); //代码运行结果是3 return 0; } / / arr[2] <==> *(arr+2) <==> *(p+2) <==> *(2+p) <==> *(2+arr) <==> 2[arr] // p[2] <==> *(p+2) // []是一个操作符 ,2和arr是两个操作数 四.二级指针 //二级指针 #include<stdio.h> int main(void) { int a = 10; //pa 是指针变量,一级指针,pa指向了
❤博客主页:折枝寄北-CSDN博客 ❤专栏:C语言学习专栏 在上一篇博客文章:C指针之舞——指针探秘之旅-CSDN博客中,我们学习了字符指针,指针数组,数组指针,数组传参和指针传参等内容,下面进一步学习 1.函数指针数组 函数指针就是一个指针,指针中所保存的地址中的内容是一个函数,同之前说过的数组指针相似,函数指针的定义为: 返回类型 (* 指针名) (函数参数) //eg: int (*pc) 1.先看 void ( * ) ( ) ,这是一个标准的函数指针,函数返回类型为void,无函数参数 2.再看蓝色括号,该括号的代表强制转换,例如:(float)3 指的是将int类型的3转换为float ,相当于调用函数 所以该代码是一次函数调用,调用的是一个返回类型为void,无函数参数,函数名为0 的一个函数 2.回调函数 定义:回调函数是利用函数指针调⽤的函数,通俗来讲,只要是一个函数参数里面有函数指针 例如:完成一个简易的计算器,要求输入1代表计算加法,2代表计算减法,3代表计算乘法,4代表计算除法,0代表退出计算器,选择1 2 3 4其中一个后输入要计算的两个数字,返回计算结果 当不使用回调函数的代码如下
int sz1 = sizeof(arr) / sizeof(arr[0]); test1(arr); test2(arr); return 0; } 如果对指针在VS不同环境是不同大小不清楚的 x : y; } int main() { //数组指针 int arr[6] = { 1,2,3,4,5,6 }; int(*p1)[6] = &arr; //函数指针 int a = 10 ; int b = 20; int(*p2)(int, int) = &Max; int(*p3)(int x, int y) = &Max; return 0; } p2,p3先与*结合说明是一个指针变量 (int ,int) ——指向函数的参数类型和个数的交代 【也可以写成(int x,int y)】 p2,p3 ——函数指针变量名 int b);//函数调用 //函数名其实就是函数的地址 int ret2 = (*p)(a, b);//使用函数指针变量 //对p解引用找到这个函数 int ret3 = p(a, b); //
main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int sz = sizeof(arr) / sizeof(arr[0]); int* p = 代码展示: int main() { int arr[10]={1,2,3,4,5,6,7,8,9,10}; int (*p)[10]=&arr; for(int i=0;i<10;i int a=10; int* p1=&a; int** p2=&p1; 对指针变量p2来说,它先于*结合,证明他是一个指针,再与int*结合,证明它所指向的对象是整形指针类型,是一个二级指针。 int* arr[10];//arr先于[10]结合,说明它是一个数组,再与int*结合,说明它的元素类型是int* 指针数组模拟二维数组 这里,arr1就是一维数组arr1首元素地址, 同理,arr2 int arr1[3]={1,2,3}; int arr2[3]={2,3,4}; int arr3[3]={3,4,5}; int *arr[3]={arr1,arr2,arr3};
2.&数组名,这里的数组名表示整个数组,取出整个数组的地址。整个数组的地址和数组首元素地址是完全不一样的。 除去上面的特殊情况,其他地方使用数组名,都是首元素地址。 答案是不能,上面已经提到了,你创建的用来接收数组名的形参本质上是个指针,指针的大小只与环境有关(X64下是8个字节,X86是4个字节)。 所以在函数内部是计算不出数组的大小的。 三.二级指针 指针变量是变量,既然是变量,那就是地址。 我们用二级指针来接收一级指针变量的地址。 ,有关二级指针的运算,我们可以通过*p2,也就是对p2进行解引用找到p1,再对p1解引用找到n,从而对n进行修改。 四.指针数组 指针数组就是存放指针的数组。 指针数组容易与数组指针混淆,前者是数组,后者是指向数组的指针。 那么指针数组有什么用吗? 下面我们就用指针数组来模拟二维数组: 关于指针的第二篇写完了,有缘再会,拜拜。 摸鱼摸鱼✨
看代码: void test() { printf("hello\n"); } //下面pfun1和pfun2哪个有能力存放test函数的地址? void (*pfun1)(); void *pfun2() 答案是: pfun1可以存放; 首先,能给存储地址,就要求pfun1或者pfun2是指针,那哪个是指针? pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参 数,返回值类型为void。 那void *pfun2()是什么呢? 代码2解析: void(*)(int) —— 函数指针类型:参数:int;返回值:void(无返回值); signal(int, void(*)(int)) —— signal 函数的参数; void { return (*(int*)p1 - *(int*)p2); } //交换函数 // 使用char*按字节交换数据,适用于任意类型 void swap(void* p1, void* p2,
指针±整数 数组在内存中是连续存储的,只要知道第一个元素的地址,后面的元素依次就能找到。 int arr[]={1,2,3,4,5}; 而所对应的下标为0,1,2,3,4。 在对不同类型指针变量加减时结果不同, 举个例子: #include <stdio.h> int main() { int n = 10; int* p1 = &n; char* p2 = &n; p2+1); return 0; } 在下面为结果 int类型的就跳过了4个字节, char类型就跳过1个字节 结论: 指针的类型决定了,指针加减整数时,一次性跳过多少个字节。 2. 指针-指针 在指针变量相同类型时,计算出的是中间间隔的个数。 int ret = p1-p2 ; printf("%d\n", ret); return 0; } 结果为 指针类型不同时不能进行指针的加减运算。
2. &数组名:这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素地址是有区别的)。 <2>二维数组 一维数组的数组名是数组首元素的地址,那二维数组呢? 我们知道,一个整形数组,存放的都是整型数组;一个字符数组,存放的都是字符; 那存放指针类型的数组,其实就是指针数组。 指针数组中每一个元素都是地址,又可以指向一块内存。 六、指针数组模拟二维数组 #include <stdio.h> int main() { int arr1[] = {1,2,3,4,5}; int arr2[] = {2,3,4,5,6}; int 对于二维数组,用指针数组也可以来实现二维数组,但是指针数组中每个元素所指向的一维数组不是连续的。
3、指针变量类型的意义 既然指针变量的大小与类型没有关系,那为什么还要有不同的指针类型呢? 在某些情况下,指针类型还是有很大意义的。 3.1指针的解引用 这里来举一个例子探讨指针变量类型的意义。 因为,指针类型决定了对指针解引用的时候有多大的权限,也就是一次能操作几个字节。这就是指针变量类型的意义。 3.3void *类型 在指针类型中有一种特殊的类型是 void * 类型的,为无具体类型的指针(泛型指针),这种类型的指针可以用来接收任意类型的地址。 既然指针的解引用可以间接地去改变const修饰的变量的值,那我们干脆把指针变量也用const修饰,因为指针变量也是变量嘛。
2 const 修饰指针变量 2.1种类(三种): ⼀般来讲const修饰指针变量,可以放在*的左边,也可以放在*的右边,也可以同时放在*两边,意义是不⼀样的。 2形成原因(1. 指针未初始化、2. 指针越界访问3. arr的范围时,p就是野指针 *(p++)=i } return 0; } 2.3 指针指向的空间释放 3 如何规避野指针(1 指针初始化、2 ⼩⼼指针越界、3 指针变量不再使 2 语法 assert(p != NULL ); 当代码在程序中运⾏到这⼀⾏语句时,就会验证变量 p 是否等于 NULL 。 四 指针传址调⽤ 1分类:(分为传值调⽤和传址调⽤)。 2 传值调⽤ 你为啥会出现上面结果呢?
小结:数组名是数组首元素的地址,但是有2个例外。 再解释一下:这就类似于1+2=2+1,对1和2应用+操作符,1和2哪个在前都无所谓,所以i和arr那个在前都无所谓只是i[arr]的形式真的没什么可读性,更没什么人写那为什么下标引用操作符[]里既可以放数组名 (arr)/sizeof(arr[0]);printf("sz2=%d\n",sz2);}intmain(){intarr[10]={1,2,3,4,5,6,7,8,9,10};intsz1=sizeof 一级指针存其他变量(不是指针的),二级指针存一级指针的地址一级指针就是我们上面一直讲的指针(地址编码)如果说一级指针定义的时候要一个星号,比如intp1;那么二级指针定义的时候要两个星号,比如int*p2 ,指针变量又各自指向了一个地址,这就间接地指向了各个变量指针数组模拟⼆维数组展开代码语言:TXTAI代码解释#include<stdio.h>intmain(){intarr1[]={1,2,3,4,5
进一步理解指针2:双指针、指针数组和数组指针.pdf 1. 概念 1.1. 指针 对于“p + 1”,这里的“1”是啥? 双指针 指向一个指针的指针。 1.2. 指针数组 由指针值组成的数组,也就是说数组的每个元素值的数据类型均为指针类型,如:int* p[2]; 1.3. 数组指针 指向一个数组的指针。 2. 区别 行数 列数 说明 int** p1; 双指针 不固定 不固定 列数和行数都不确定,而且每行可以列数不等。 int* p2[3]; 指针数组 固定 不固定 共3行,每行多少列不确定,而且每行可以列数不等。 int (*p3)[3]; 数组指针 不固定 固定 共3列,多少行不确定。 3. 假设: int** b1; int** b2 = b1 + 1; 上述中的“1”实际是多少?这个就要看b1的类型是什么?在这里,b1是一个双指针,也就是指向指针的指针。
if (p1 == p2) { printf("p1==p2\n\n"); } else printf("p1! =p2\n\n"); return 0; } 运行结果: 结果显示: 当多个指针指向同一个常量字符串时,它们的地址值相同, 同一个常量字符串他们在内存中占用一块空间 2.数组指针变量 ( 1)指针与数组 数组名是首元素地址 arr == &arr[0] ; 但是也有例外: 1.sizeof( arr ) ;这里计算的是整个数组 2. [ i ] ; (2)数组指针变量 创建一个数组指针变量: int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int (*p)[10] = &arr; 在上面代码中, 赋值方式:可以直接将函数名赋给指针变量(函数名即地址),如 pf = Add 调用方法:通过指针调用函数时,可以使用 ( * pf ) ( arg1, arg2 ) 或简写 pf ( arg1 , arg2