C语言笔记-指针

目录

第六章到了最刺激的指针

第一个指针变量

第二个指针变量 

第三个为什么要用指针之1

第一不使用指针可以看到是无法改变真正的值

 第二种指针方式直接操作内存地址 

第四个指针-指向固定地址

 第五个 输入三个数a,b,c; 要求不管怎么输入,在输出的时候,a,b,c就是由大到小的顺序输出,用函数封装实现

 第6个通过指针引用数组

6.1定义一个指针变量指向数组,指针偏移遍历数组,指针偏移的补充,记得回到数组首地址,

6.2指针和数组名的,重要面试 

第七个通过编程验证认知

 第八个二维数组的地址写法应用;

 第九数组指针

 第十个数组指针和二维数组的应用

第11个函数指针认知

 int 型有返回值的函数指针

 第12个函数指针-回调函数

 第13个指针数组的概念

 第14个指针函数

               指针函数概念

  第15个二级(多级)指针

 为什么要用二级指针

 二级指针不能简单粗暴指向二维数组

 函数总结



第六章到了最刺激的指针

    1. 认识它
        1. 指针==地址
        2. 地址
          int   a = 10
          类型,变量名,内存地址,值
          变量名能访问
          通过地址也能访问
          & 取地址运算符
          * 将地址内的值读出运算符
          引入,

第一个指针变量

  • int a = 10; 声明了一个整型变量 a 并赋值为 10。
  • printf("a = %d\n", a); 打印了变量 a 的值,使用 %d 格式化输出整型值。
  • printf("a的地址是:%p\n", &a); 打印了变量 a 的地址,使用 %p 格式化输出地址。
  • printf("a = %d\n", *(&a)); 打印了变量 a 地址中的数据,使用 * 取值运算符,将地址 &a 中存储的数据取出来并格式化输出。
  • 如何定义一个指针变量* 的标识作用
#include <stdio.h>
 
int main()
{
	//什么是整形变量,存放整型数的变量
	//什么是字符变量,存放字符型数据的变量
	//什么是指针变量,存放指针的变量
	//什么是指针变量,存放地址的变量 
	int a = 10;
	int *p;
	p = &a;//*p = &a(不可以这么使用指针)[Warning] assignment makes integer from pointer without a cast
	//警告]赋值在没有强制类型转换的情况下从指针生成整数
	printf("变量名直接访问 a = %d\n",a);
	printf("a的地址是:0x%p\n",&a);
	printf("地址访问:a = %d\n",*(&a));//*(&a)取值运算符,他们后面跟的内存地址中的数据
										//取出来, 地址访问 
	printf("指针变量的方式访问a:%d\n",*p); 
	return 0;
}

 

第二个指针变量 ==存放地址的变量

只产生在指针变量定义或声明的时候
如何使用一个指针变量
变量访问的两种方式

既然指针变量是存放别人地址的变量,
那什么要区分类型呢

      1. 指针变量==存放地址的变量
  • int a = 0x1234; 声明一个整型变量 a 并赋值为十六进制数 0x1234。
  • int *p = &a; 声明一个整型指针 p 并将其指向变量 a 的地址。
  • char *c = &a; 声明一个字符指针 c 并将其指向变量 a 的地址。注意,指针类型可以根据需要进行转换。
  • printf("p = %p\n", p); 打印指针变量 p 的值,使用 %p 格式化输出地址。
  • printf("c = %p\n", c); 打印指针变量 c 的值,同样使用 %p 格式化输出地址。
  • printf("a = %x\n", *p); 打印指针 p 所指向地址中的整型数据,使用 %x 格式化输出十六进制数。
  • printf("a = %x\n", *c); 打印指针 c 所指向地址中的字符数据,同样使用 %x 格式化输出十六进制数。
  • printf("++p = %p\n", ++p); 打印 p 指针自增后的值,注意 ++p 会使指针指向下一个地址。
  • printf("++p = %p\n", ++c); 打印 c 指针自增后的值,同样会使指针指向下一个地址。
  • 演示了指针的用法,包括指针的声明与初始化、指针指向的地址和指针指向地址中数据的访问。在这个例子中,指针 p 指向变量 a 的地址,并通过 *p 来访问这个地址中存储的整型数据。指针 c 同样指向变量 a 的地址,但是通过 *c 访问时,将地址中的数据作为字符来处理。
  • 第一行和第二行输出了指针变量 p 和 c 的地址,这两个指针指向变量 a 的地址。第三行和第四行输出了通过指针访问变量 a 的数据,其中第四行输出只显示了低位字节。最后两行输出了自增指针后的地址,注意指针 p 自增了 4 个字节,而指针 c 自增了 1 个字节。
#include <stdio.h>
 
int main()
{
	int a = 0x1234;
	int *p = &a;
	char *c = &a;
	
	printf("p = %p\n",p);
	printf("c = %p\n",c);
	
	printf("a = %x\n",*p);
	printf("a = %x\n",*c);
	
	printf("++p = %p\n",++p);
	printf("++p = %p\n",++c);
	
	return 0;
 } 

 

第三个为什么要用指针之1

第一不使用指针可以看到是无法改变真正的值

#include <stdio.h>
 
void chageData(int data,int data2)
{
	int tmp;
	tmp = data;
	data = data2;
	data2 = tmp;
}
 
int main()
{
	int data = 100;
	int data2 = 50;
	
	printf("交换前:data = %d\n",data);
	printf("交换前:data2 = %d\n",data2);
	
	chageData(data,data2);
	
	printf("交换后:data = %d\n",data);
	printf("交换后:data2 = %d\n",data2);
	return 0;
}

 第二种指针方式直接操作内存地址 

#include <stdio.h>
 
void chageData(int *pdata,int *pdata2)
{
	int tmp;
	tmp = *pdata;
	*pdata = *pdata2;
	*pdata2 = tmp;	
}
 
int main()
{
	int data = 100;
	int data2 = 50;
	
	printf("交换前:data1=%d,data2=%d\n",data,data2);
	printf("交换前:data1=%p,data2=%p\n",data,data2);
		
	chageData(&data,&data2); 
	
	printf("交换后:data1=%d,data2=%d\n",data,data2);
	printf("交换前:data1=%p,data2=%p\n",data,data2);	
	return 0;
}

 

  •  void changeData(int *pdata, int *pdata2) 定义了一个函数 changeData,它接受两个整型指针作为参数。
  • int tmp; tmp = *pdata; *pdata = *pdata2; *pdata2 = tmp; 在函数内部,先声明一个临时变量 tmp,然后通过指针交换传入的两个变量的值。
  • int main() 主函数开始。
  • int data = 100; int data2 = 50; 声明并初始化两个整型变量 data 和 data2。
  • printf("交换前:data1=%d, data2=%d\n", data, data2); 打印输出交换前的两个变量的值。
  • printf("交换前:data1=%p, data2=%p\n", data, data2); 打印输出交换前的两个变量的地址,注意使用 %p 格式化输出地址。
  • changeData(&data, &data2); 调用 changeData 函数来交换变量 data 和 data2 的值,传入的参数是变量的地址。
  • printf("交换后:data1=%d, data2=%d\n", data, data2); 打印输出交换后的两个变量的值。
  • printf("交换后:data1=%p, data2=%p\n", data, data2); 打印输出交换后的两个变量的地址。
  • 指针参数来实现变量值的交换。在函数 changeData 中,通过操作指针来修改变量的值,从而实现了变量值的交换。注意在 main 函数中传递参数给 changeData 函数时需要使用地址运算符 & 来获取变量的地址。
  • 第一行和第二行输出了交换前的两个变量的值和地址。第三行和第四行输出了交换后的两个变量的值和地址。可以看到,通过指针参数交换了变量 data 和 data2 的值。

第四个指针-指向固定地址

  • 这段代码是一个简单的C程序,它打印了一个整数变量`data`的内存地址,并将一个指针`p`指向该地址。
  • 首先,在程序开始时,定义了一个整型变量`data`并赋值为20。
  • 接下来,通过`printf`函数打印了变量`data`的内存地址,使用了格式控制符`%p`来打印指针的值。`&data`表示变量`data`的地址。在这个例子中,打印出来的地址是`0x000000000062FE1C`。
  • 然后,定义了一个`volatile`修饰符的无符号整型指针`p`,并将其初始化为一个指定的内存地址`0x000000000062FE1C`。指针类型被转换为`volatile unsigned int *`,这通常是为了告诉编译器不要对指针所指向的数据做优化。
  • 最后,程序返回0,表示顺利执行完成。
  • 需要注意的是,这段代码中直接给指针`p`赋值一个具体的内存地址是不推荐的,因为操作系统会限制用户程序对内存的直接访问。在一般情况下,我们应该通过合适的库函数或系统调用来分配内存或获取有效的指针。
#include <stdio.h>
 
int main()
{
	int data = 20;
	
	printf("data = 0x%p\n",&data);//data = 0x000000000062FE1C
	volatile unsigned int *p = (volatile unsigned int *)0x000000000062FE1C;
	//指向固定的内存地址 
	printf("p = 0x%p\n",p);
	return 0;	
} 

 第五个 输入三个数a,b,c; 要求不管怎么输入,在输出的时候,a,b,c就是由大到小的顺序输出,用函数封装实现

  •  使用C语言实现的程序,实现了输入三个整数,并按从大到小的顺序进行排序后输出的功能。
  • 程序中定义了两个辅助函数,swap函数用于交换两个数的值,sortDescending函数用于将三个数按从大到小的顺序进行排序。
  • 在主函数main中,首先通过printf函数输出提示信息,让用户输入三个整数。然后通过scanf函数从用户输入中获取这三个整数的值,并将其赋值给变量a、b、c。
  • 接下来,调用sortDescending函数,通过传递参数的地址,将a、b、c的值传递给函数,并在函数内部进行排序操作。
  • 最后,通过printf函数按照从大到小的顺序输出排序后的结果,以%d格式输出变量a、b、c的值。
  • 这段代码使用了指针和函数封装,通过传递指针参数来实现对变量的修改,将排序后的结果正确输出

#include <stdio.h>
 
void swap(int *a,int *b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}
 
void sortDescending(int *a,int *b,int *c)
{
	if(*a < *b)
		swap(a,b);
	if(*a < *c)
		swap(a,c);
	if(*b < *c)
		swap(b,c); 
}
int main()
{
	int a,b,c;
	
	printf("请输入三个数:\n");
	scanf("%d%d%d",&a,&b,&c);
	
	sortDescending(&a,&b,&c);
	
	printf("交换后输出的数据是:a = %d,b = %d,c = %d\n",a,b,c);
	return 0;
 } 

 

 第6个通过指针引用数组

6.1定义一个指针变量指向数组,指针偏移遍历数组,指针偏移的补充,记得回到数组首地址

 

 

 

#include <stdio.h>

int main()
{
	int arr[3] = {1,2,3};
	int *p;
	int i;
	
	//p = &arr[0];//数组的首地址就是首元素的地址 
	p = arr;//数组名就是数组的首地址 
	
	/*printf("0首元素是: %d\n",*p);
	printf("1首元素是: %d\n",*(p+1));
	printf("2首元素是: %d\n",*(p+2));
	*/ 
	for( i = 0; i < 3; i++){
		//printf("address:0x%p  p = %d ",p+1,*(p+i));
		printf("%d ",*p);
		p++; 
	}
	p = arr;
	for( i = 0; i < 3; i++){
	//printf("address:0x%p  p = %d ",p+1,*(p+i));
		printf("%d ",*p);
		p++; 
	}
	return 0;
}

6.2指针和数组名的,指针通过sizeof类型来计算大小

#include <stdio.h>

int main()
{
	int arr[3] = {1,2,3};//指针常量不可改变
	int *p = &arr;//指针变量可以改变
	int i;
	
	printf("sizeof arr is %d\n",sizeof(arr));//3*4=12
	printf("sizeof p_arr is %d\n",sizeof(p));//os 用8个字节表示一个地址 
	printf("sizeof int  is %d\n",sizeof(int));
	printf("sizeof pointer is %d\n",sizeof(int *));//os 用8个字节表示一个地址  
	printf("sizeof pointer is %d\n",sizeof(char *));//os 用8个字节表示一个地址 
	
	putchar('\n'); 
	
	printf("arr = %d \n",*arr);
	printf("p = %d \n",*p);
	printf("p = %d \n",p[2]);
	
	putchar('\n');
	for(i = 0; i < 3; i++){
		printf("p = %d ",p[i]);//p[i] 
	}
	
	putchar('\n');
	
	for(i = 0; i < 3; i++){
		printf("arr = %d ",*(arr+i));//括号*(arr+i) 
	}
	
	putchar('\n');
	
	for(i = 0; i < 3; i++){
		printf("p++ = %d ",*p++);//for_p++实现 
	}
	/*for(i = 0; i < 3; i++){
		printf("*arr = %d ",*arr++));//括号*arr++指针常量 */ //编译不过,指针常量
				
	return 0;
 } 

第七个通过编程验证认知

#include <stdio.h>

int main()
{
    int arr[3][4] = {{11,22,33,44},
                     {12,13,15,16},
                     {22,66,77,88}};

    printf("arr是父亲地址:%p,偏移1后是%p\n",arr, arr+1);
    printf("arr[0]是子数组地址;%p,偏移1后是%p\n",arr[0],arr[0]+1);
    printf("arr[0]是子数组地址;%p,偏移1后是%p\n",*(arr+0),*(arr+0)+1);
    return 0;
}

 第八个二维数组的地址写法应用;

//二维数组的地址写法应用:
printf("add:0x%p,data:%d \n",*(arr+i)+j,*(*(arr+i)+j));
#include <stdio.h>


int main()
{
    int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};
    int i;
    int j;

    for(i=0;i<3;i++){
        for(j=0;j<4;j++){
            printf("add:0x%p,data:%d \n",&arr[i][j],arr[i][j]);
            printf("add:0x%p,data:%d \n",arr[i]+j,*(arr[i]+j));
            printf("add:0x%p,data:%d \n",*(arr+i)+j,*(*(arr+i)+j));
            printf("===========================================\n");
        }
        putchar('\n');
    }
    return 0;
}

 第九数组指针

#include <stdio.h>

//arr,arr[0]
int main()
{
    int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};//arr+
    int i,j;
    int *p;//p++
//	p = &arr[0][0];
    //p = arr;
    //能不能定义一个指针,让指针偏移的时候,也偏移对应大小的数组?
    //数组指针,定义一个指针,指向一个数组!
    //数组指针才是真正等同于二维数组名
    int (*p2)[4];
    p2 = arr;
	printf("p2=%p\n",p2);
	printf("++p2=%p\n",++p2);
    for(i=0;i<3;i++){
        for(j=0;j<4;j++){
            //printf("%d\n",*(*(p2+i)+j));
            //printf("%d\n",*(*(arr+i)+j));

        }

    }
}

 第十个数组指针和二维数组的应用

代码解释如下:

  1. getTheData 函数是用于获取二维数组中指定行列位置的值。它接收一个指向二维数组的指针 p,以及指定的行列索引 hang 和 lie。首先通过 p+hang 定位到指定的行,然后通过 *(p+hang)+lie 定位到指定的列,最后通过 *(*(p+hang)+lie) 获取该位置的值,并将其返回。

  2. tipsInputHangLie 函数用于提示用户输入行列值。它接收两个参数 pm 和 pn,分别表示输入的行和列。通过 scanf 函数从用户输入中获取行列值,并将其保存到 pm 和 pn 中。

  3. main 函数是程序的入口函数。首先定义一个二维数组 arr,其中包含一些随机的整数。然后定义变量 ihang 和 ilie,用于存储用户输入的行列值。接下来依次执行以下步骤:

    • 调用 tipsInputHangLie 函数提示用户输入行列值,并将用户输入的值存储到 ihang 和 ilie 中。
    • 调用 getTheData 函数获取二维数组 arr 中指定行列位置的值,并将结果保存到 data 变量中。
    • 使用 printf 函数将行列值以及对应位置的值输出到屏幕上。

最后,编译并运行该程序,用户将被要求输入行列值,程序将输出对应位置的值。

#include <stdio.h>

int getTheData(int (*p)[4],int hang,int lie)
{
    int data;
    data = *(*(p+hang)+lie);
    return data;
    //return p[hang][lie];
}
void tipsInputHangLie(int *pm, int *pn)
{
    printf("输入行列值:\n");
    scanf("%d%d",pm,pn);
    puts("done!");
}
//arr,arr[0]
int main()
{
    int arr[3][4] = {{11,22,33,44},
                     {12,13,15,16},
                     {22,66,77,88}};//arr+
    int ihang,ilie;
    int data;

    //1. 提示用户输入行列值
    tipsInputHangLie(&ihang,&ilie);
    //2. 找出对应行列值的那个数
    data = getTheData(arr,ihang,ilie);
    //3. 打印出来
    printf("%d行%d列的值是%d\n",ihang,ilie,data);
}

第11个函数指针认知

代码解释如下:

  • 1. `printWelcome` 函数用于输出欢迎信息。它使用 `puts` 函数将字符串 "认知超前,扬帆起航" 输出到屏幕上。
  • 2. `main` 函数是程序的入口函数。首先定义一个整数变量 `a`,并赋值为 10。然后定义一个整型指针变量 `pa`,并将 `pa` 指向 `a` 的地址。
  • 3. 使用 `printf` 函数将变量 `a` 的值直接输出到屏幕上。`%d` 是格式化输出的占位符,表示输出一个整数。`a` 表示输出变量 `a` 的值。
  • 4. 使用 `printf` 函数将指针变量 `pa` 指向的内存地址的值输出到屏幕上。`*pa` 表示取指针 `pa` 指向的内存地址中的值,即变量 `a` 的值。
  • 5. 定义一个函数指针变量 `p`,它指向无返回值且无参数的函数。函数指针的声明方式为 `返回值类型 (*指针变量名) (参数列表)`。这里的 `void(*p)()` 表示 `p` 是一个函数指针,指向一个参数列表为空且返回值类型为 `void` 的函数。
  • 6. 将函数 `printWelcome` 的地址赋值给函数指针变量 `p`。这样,`p` 就指向了函数 `printWelcome`。
  • 7. 通过函数指针 `p` 调用函数 `printWelcome`,输出欢迎信息。
  • 8. 通过 `(*p)()` 的形式,也可以通过函数指针 `p` 间接调用函数 `printWelcome`,输出欢迎信息。`(*p)()` 中的 `*p` 表示取函数指针 `p` 的值,即函数 `printWelcome` 的地址。
  • 9. 最后,使用 `return 0;` 表示程序正常结束,并返回值 0。
  • 请注意,代码中对函数指针 `p` 的调用方式有两种形式,分别是 `p()` 和 `(*p)()`,二者等价。
#include <stdio.h>

void printWelcome()
{
	puts("认知超前,扬帆起航"); 
}
int main()
{
	int a = 10;
	int *pa = &a;
	printf("%d\n",a); //直接访问
	printf("%d\n",*pa);//间接访问,*p取内容 
	void(*p) ();//定义一个函数指针变量
	p = printWelcome;//指向函数 
	printWelcome();//普通函数调用 
	(*p) ();//指针函数调用 (*p)()取内容函数跟*p地址一样 
	return 0;
}

 int 型有返回值的函数指针

代码解释如下:

1. `inCDdata` 函数是一个整型函数,接收一个整数参数 `data`。函数的作用是将参数 `data` 的值加 1,并将计算结果返回。

2. `printWelcome` 函数用于输出欢迎信息。它使用 `puts` 函数将字符串 "第一个,启动" 输出到屏幕上。

3. `main` 函数是程序的入口函数。首先定义一个函数指针变量 `p`,它指向一个无返回值且无参数的函数。

4. 将函数 `printWelcome` 的地址赋值给函数指针变量 `p`,使得 `p` 指向该函数。

5. 通过 `(*p)()` 的形式,通过函数指针 `p` 间接调用函数 `printWelcome`,输出欢迎信息。

6. 定义一个整型函数指针变量 `p2`,它指向一个具有一个整数参数和整数返回值的函数。

7. 将函数 `inCDdata` 的地址赋值给函数指针变量 `p2`,使得 `p2` 指向该函数。

8. 使用 `(*p2)(10)` 的形式,通过函数指针 `p2` 间接调用函数 `inCDdata`,并传递参数值为 10。函数返回的计算结果 11 会被打印输出到屏幕上。

9. 使用 `(*p2)(10)` 的形式再次通过函数指针 `p2` 调用函数 `inCDdata`,但这次没有用 `printf` 函数打印输出结果。

10. 最后,使用 `return 0;` 表示程序正常结束,并返回值 0。

请注意,代码中通过函数指针变量 `p` 和 `p2` 分别间接调用了函数 `printWelcome` 和 `inCDdata`,实现了通过函数指针来调用不同函数的功能。另外,通过 `(*p)()` 和 `(*p2)(10)` 的形式,可以使用函数指针调用相应的函数。
#include <stdio.h>

int inCDdata(int data)
{
	return ++data;
	
} 
void printWelcome()
{
	puts("第一个,启动"); 
}
int main()
{
	void (*p) ();
	p = printWelcome;
	(*p) ();
	
	int (*p2) (int data);
	p2 = inCDdata;
	printf("p2测试:%d\n",(*p2)(10));
	//(*p2) (10);
	return 0;
}

 第12个函数指针-回调函数

代码解释如下:

1. `getMax` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`。函数的作用是比较两个参数的大小,返回较大的值。

2. `getMin` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`。函数的作用是比较两个参数的大小,返回较小的值。

3. `getSum` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`。函数的作用是将两个参数相加,返回它们的和。

4. `dataHandler` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`,以及一个函数指针 `pfunc`,该函数指针指向具有两个整数参数和整数返回值的函数。函数的作用是通过函数指针间接调用相应的函数,并将 `data1` 和 `data2` 作为参数传递给该函数,返回函数的结果。

5. `main` 函数是程序的入口函数。首先定义整数变量 `a` 和 `b`,并给它们赋值为 10 和 20。然后定义整数变量 `cmd` 和 `ret`。

6. 定义一个函数指针变量 `pfunc`,该函数指针指向具有两个整数参数和整数返回值的函数。

7. 使用 `printf` 函数提示用户输入命令,根据用户输入的命令值 `cmd` 进行不同的操作。用户可以输入 1(取最大值)、2(取最小值)或 3(求和)。

8. 使用 `scanf` 函数获取用户输入的命令值,将其存储到变量 `cmd` 中。

9. 使用 `switch` 语句根据用户输入的命令值 `cmd` 来选择合适的函数指针。如果 `cmd` 的值是 1,则将函数指针 `pfunc` 指向 `getMax` 函数;如果 `cmd` 的值是 2,则将函数指针 `pfunc` 指向 `getMin` 函数;如果 `cmd` 的值是 3,则将函数指针 `pfunc` 指向 `getSum` 函数。

10. 调用 `dataHandler` 函数,传入参数 `a`、`b` 和函数指针 `pfunc`,将函数指针 `pfunc` 间接调用相应的函数,并将 `a` 和 `b` 作为参数传递给该函数,返回函数的结果。将结果存储到变量 `ret` 中。

11. 使用 `printf` 函数打印输出变量 `ret` 的值。

12. 最后,使用 `return 0;` 表示程序正常结束,并返回值 0。

请注意,在该代码中,通过函数指针可以实现根据用户的输入动态选择调用不同的函数,实现了更灵活的函数调用。
#include <stdio.h>

int getMax(int data1,int data2)
{	
	return 	data1<data2 ? data1:data2;
} 
int getMin(int data1,int data2)
{
	 return data1<data2 ? data1:data2;
}
int getSum(int data1,int data2)
{
	return data1+data2;
}

int dataHandler(int data1,int data2, int (*pfunc) (int data1,int data2))
{
	int ret;
	ret = (*pfunc) (data1,data2);
	return ret;
}
int main()
{
	int a = 10;
	int b = 20;
	int cmd;
	int ret;
	
	int (*pfunc) (int data1,int data2); 
	
	printf("请输入1(取最大值),2(最小值),或者3(求和)\n");
	scanf("%d",&cmd);
	switch(cmd){
		case 1:
			pfunc = getMax;
			break;
		case 2:
			pfunc = getMin;
		case 3:
			pfunc = getSum;
			break;
		default:
			printf("输入错误!@输入1(取大值),2(取小值),或者3(求和)\n");
			//exit(-1);
		break;
	}
	ret = dataHandler(a,b,pfunc);
	
	printf("ret = %d\n",ret);
	return 0;
}

 第13个指针数组的概念

代码解释如下:

1. `main` 函数是程序的入口函数。首先定义整数变量 `a`、`b`、`c` 和 `d`,并给它们分别赋值为 10、20、30 和 40。然后定义整数变量 `i`,用于循环计数。

2. 定义一个指针数组 `p`,其中包含了4个指针元素。这些指针元素分别指向变量 `a`、`b`、`c` 和 `d`。

3. 使用 `printf` 函数和循环语句,依次输出指针数组 `p` 中每个指针元素所指向的变量的值。通过 `*p[i]` 可以获取指针数组 `p` 中第 `i` 个指针元素所指向的变量的值。

4. 最后,使用 `return 0;` 表示程序正常结束,并返回值 0。

这段代码的作用是使用指针数组来访问并输出各个变量的值。通过循环遍历指针数组 `p`,并通过解引用符 `*` 获取指针元素所指向的变量的值,并使用 `printf` 函数输出到屏幕上。
#include <stdio.h>

int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int d = 40;
	int i;
	
	int* p[4] = {&a,&b,&c,&d};
	
	for(i = 0; i < 4; i++){
		printf("%d ",*p[i]);
	}
	return 0;
}

 

代码解释如下:

  • 1. `getMax` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`。函数的作用是比较两个参数的大小,返回较大的值。
  • 2. `getMin` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`。函数的作用是比较两个参数的大小,返回较小的值。
  • 3. `getSum` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`。函数的作用是将两个参数相加,返回它们的和。
  • 4. `dataHandler` 函数是一个整型函数,接收两个整数参数 `data1` 和 `data2`,以及一个函数指针 `pfunc`,该函数指针指向具有两个整数参数和整数返回值的函数。函数的作用是通过函数指针间接调用相应的函数,并将 `data1` 和 `data2` 作为参数传递给该函数,返回函数的结果。
  • 5. `main` 函数是程序的入口函数。首先定义整数变量 `a` 和 `b`,并给它们赋值为 10 和 20。然后定义整数变量 `ret` 和 `i`。
  • 6. 定义一个函数指针数组 `pfunc`,其中包含了 3 个函数指针元素。这些函数指针元素分别指向 `getMin`、`getMax` 和 `getSum` 函数。
  • 7. 使用循环语句,遍历函数指针数组 `pfunc`。在每次循环中,使用函数指针 `pfunc[i]` 间接调用相应的函数,传入参数 `a` 和 `b`,获取函数的结果,并将结果赋值给变量 `ret`。
  • 8. 使用 `printf` 函数将变量 `ret` 的值打印输出到屏幕上。
  • 9. 最后,使用 `return 0;` 表示程序正常结束,并返回值 0。
  • 这段代码的作用是使用函数指针数组来循环调用不同的函数,并获取函数的结果。通过循环遍历函数指针数组 `pfunc`,在每次循环中,通过函数指针 `pfunc[i]` 间接调用相应的函数,传入参数 `a` 和 `b`,获取函数的结果,并将结果存储到变量 `ret` 中,然后使用 `printf` 函数输出结果到屏幕上。
#include <stdio.h>

int getMax(int data1,int data2)
{	
	return 	data1<data2 ? data1:data2;
} 
int getMin(int data1,int data2)
{
	 return data1<data2 ? data1:data2;
}
int getSum(int data1,int data2)
{
	return data1+data2;
}

int dataHandler(int data1,int data2, int (*pfunc) (int data1,int data2))
{
	int ret;
	ret = (*pfunc) (data1,data2);
	return ret;
}
int main()
{
	int a = 10;
	int b = 20;
	int ret;
	int i;
	
	int (*pfunc[3]) (int ,int )={getMin,getMax,getSum}; 
	for(i = 0; i < 3; i++){
		ret = (*pfunc[i]) (a,b);
		printf("ret = %d\n",ret);
	}
	//ret = dataHandler(a,b,pfunc);
	
	
	return 0;
}

 第14个指针函数

               指针函数概念

 

1、定义一个二维整型数组scores,其中包含3个学生的4门课程成绩。

2、定义整型指针ppos、整型变量pos和循环计数变量i。提示用户输入想要查看成绩的学生号数,然后使用scanf函数将输入的值赋给pos。

3、调用函数getPosPerson,将学生号数pos和二维数组scores传递给函数,并将返回的学生成绩数组指针赋给ppos。

4、使用循环遍历学生的成绩数组,打印出每门课程的成绩。

5、定义了一个名为getPosPerson的函数。该函数接受一个整型参数pos表示学生号数,和一个指向包含4个元素的整型指针的二维数组pstu。函数返回一个指向整型的指针。

6、函数体内部,定义了一个整型指针p。将p的地址设置为(pstu + pos),也就是指向指针数组中对应学生的地址。最后返回指针p。
#include <stdio.h>

int* getPosPerson(int pos,int (*pstu)[4])
{
	int *p;
	p = (int *) (pstu+pos);
	return p;
}
int main()
{
	int scores[3][4] = {{55,66,77,88},
					    {66,55,77,88},
					    {11,22,33,59},
					    };
	int *ppos;
	int pos;
	int i;
	printf("请输入你需要看的学生号数:0,1,2\n");
	scanf("%d",&pos);
	
	ppos = getPosPerson(pos,scores);
	for(i = 0; i < 4; i++){
		printf("%d ",*ppos++);
	}
	return 0;
 } 

 

 

#include <stdio.h>

int* getPosPerson(int pos, int (*pstu)[4])
{
    int *p;
    p = (int *) (pstu+pos);
    return p;
}

int main()
{
    int scores[3][4] = {{55, 66, 77, 88},
                        {66, 55, 77, 88},
                        {11, 22, 33, 59}
                       };
    int *ppos;
    int pos;
    int i,j;
    printf("请输入你需要看的学生号数:0, 1, 2\n");
    scanf("%d", &pos);

    ppos = getPosPerson(pos, scores);
    printf("学生%d的成绩为:", pos);
    for (i = 0; i < 4; i++) {
        printf("%d ", *ppos++);
    }
    
    printf("\n不及格的成绩和学号为:");
    for (i = 0; i < 3; i++) {
        ppos = getPosPerson(i, scores);
        for (j = 0; j < 4; j++) {
            if (*ppos < 60) {
                printf("学号%d,成绩%d ", i, *ppos);
                break;
            }
            ppos++;
        }
    }
    
    return 0;
}

  第15个二级(多级)指针

#include <stdio.h>

int main()
{
    int data = 100;
    int *p = &data;

    printf("data的地址是:%p, 内容是%d\n",&data,data);
    printf("p保存data的地址是:%p,内容是%d\n",p,*p);

    /*printf("p的地址是:%p\n",&p);
    int *pp = &p;
    printf("pp保存p的地址是:%p\n",pp);
    printf("pp是:%p\n",*pp);*/

    int **p2;
    p2 = &p;
    printf("p2保存p的地址:%p\n",p2);
    printf("p2是%p\n",*p2);
    printf("**p2来访问data的地址:%d\n",**p2);

    int ***p3;
    p3 = &p2;
    printf("p3保存p2的地址:%p\n",p3);
    printf("p3是%p2\n",*p3);
    printf("***p3来访问data的地址:%d\n",***p3);
    return 0;
}

 为什么要用二级指针

  • 这段代码主要是一个关于二维数组和指针的示例。
  • 1. `getPosPerson` 函数用于获取指定位置的学生的成绩,它接受三个参数:
  •    - `pos`:指定要获取的学生的位置
  •    - `pstu`:二维数组,存储了学生的成绩,每行代表一个学生的四门成绩
  •    - `ppos`:指向指针的指针,用于存储获取到的学生的成绩的地址
  • 2. 在 `main` 函数中,首先定义了一个二维数组 `scores`,表示三个学生的四门成绩。
  • 3. 然后定义了一个指针 `ppos` 和一个整数 `pos`。
  • 4. 用户会被要求输入一个数字,表示要查看的学生的位置。
  • 5. 调用 `getPosPerson` 函数,传入位置、二维数组和指针地址作为参数。
  • 6. `getPosPerson` 函数中,将 `pstu+pos` 的结果强制转换为指针类型,并将其赋值给 `*ppos`,即将学生的成绩的地址赋值给 `ppos`。
  • 7. 最后,在 `main` 函数中,通过循环打印通过指针访问的学生的成绩。
  • 总体来说,该代码的功能是输入一个学生位置,然后输出该学生的四门成绩。
#include <stdio.h>

void getPosPerson(int pos,int (*pstu)[4],int **ppos)
{
	*ppos = (int *) (pstu+pos);
  

}
int main()
{
	int scores[3][4] = {{55,66,77,88},
					    {66,55,77,88},
					    {11,22,33,59},
					    };
	int *ppos;
	int pos;
	int i;
	printf("请输入你需要看的学生号数:0,1,2\n");
	scanf("%d",&pos);
	
	getPosPerson(pos,scores,&ppos);
	for(i = 0; i < 4; i++){
		printf("%d ",*ppos++);
	}
	return 0;
 } 

 二级指针不能简单粗暴指向二维数组

  • 这段代码主要是关于指针和二维数组的示例。
  • 1. 首先定义了一个二维数组 `scores`,表示三个学生的四门成绩。
  • 2. 接下来定义了一个指向二维数组 `scores` 的指针 `p2`,指针类型为 `int (*)[4]`,表示指向含有4个 `int` 元素的一维数组的指针。
  • 3. 然后,定义了一个指向指针的指针 `p3`,指针类型为 `int **`。
  • 4. 在注释部分的代码中,将 `scores` 赋值给指针 `p`,并尝试打印 `p` 和 `*p` 的值。错误地先将 `p` 定义为指向指针的指针类型,而不是指向一维数组的指针类型,因此会导致地址的错误打印。正确的写法应该是 `int (*p)[4]; p = scores;`。
  • 5. 接下来的语句 `**p = 100;` 试图将 `scores` 的第一个元素设置为 `100`,但这是不正确的,因为 `p` 是一个指向二维数组的指针,不能直接访问一维数组元素的值。正确的做法是使用两级指针 `int **p3 = &p2;`,将 `p2` 的地址赋给 `p3`,然后通过 `**p3` 访问 `scores`。
  • 6. 最后,打印 `scores[0][0]` 的值,结果为 `100`。
  • 总体来说,该代码的目的是通过指针访问二维数组的元素,并使用指针的指针来修改数组元素的值。
#include <stdio.h>

int main()
{
	int scores[3][4] = {{55,66,77,88},
					    {66,55,77,88},
					    {11,22,33,59},
					    };
	int (*p2) [4] = scores;
    /*int **p;
    p = scores;
    

    printf("scores: %p\n",scores);
    printf("p = %p\n",p);
    printf("*p = %p\n",*p);//*p是一个野指针,不是我们认为的会变成列地址
    printf("scores = %p\n",*scores);//*scores是可以的,*p不行

    **p = 100;
    printf("done\n");*/

    int **p3 = &p2;
    **p3 = 100;
    printf("%d\n",scores[0][0]);
	return 0;
 } 

 常见指针函数以及定义总结

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值