首页 > 其他分享 >#include<初见C语言之指针(3)>

#include<初见C语言之指针(3)>

时间:2024-03-22 15:04:27浏览次数:22  
标签:return int C语言 初见 数组 printf 函数指针 include 指针

目录

一、字符指针变量

二、数组指针变量

1.什么是数组指针变量?

2.数组指针怎么初始化?

三、二组数组传参的本质

四、函数指针变量

1.什么是函数指针变量?

2.函数指针变量使用 

 3.有趣代码

 3.1typedef关键字

五、函数指针数组

六、转移表

总结


一、字符指针变量

字符指针变量的指针类型是char*;

一般使用:

int main()
{
    char ch = 'w';
    char* pc = &ch;
    printf("%c\n", ch);
    *pc = 'p';
    printf("%c\n", *pc);
    
    return 0;

}

%c是打印字符的,%s是打印字符串的首地址

其他用法:

int main()
{
    const char* p= "hello world";//常量字符串,是不能修改的
    printf("%c\n", *p);
    //*p = 'q';//err
    
    return 0;

}

很容易把代码hello world放在指针*p中,但是本质是把字符串的首地址放在*p中。

画图演示:

下面我们再来看看一段代码:

 #include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char* str3 = "hello bit.";
    const char* str4 = "hello bit.";
    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");

    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");

    return 0;
}

画图演示:

所以str1和str2不相同,str3和str4相同;(常量字符串,是不能修改的)


二、数组指针变量

1.什么是数组指针变量?

类比的方法:

  • 字符指针 char* p 指向字符的指针,存放的是字符地址
  • 整型指针 char* p 指向整型的指针,存放的是整型地址

所以数组指针是一种指针变量,是存放数组地址的指针变量

char ch = 'w';

char* pc =&ch;//字符指针

int n =10;

int* p =&n;//整型指针

数组指针变量

int (*p)[10];

解释:p先和*结合,说明p是一个指针变量,然后指向的是一个大小为10个整型的数组

 注意:[ ]的优先级要高于*,所以必须先加()保证p和*结合

2.数组指针怎么初始化?

在前面的学习中我们就知道,数组名是数组首元素的地址

int main()
{
    int arr[10] = { 10 };
    int(*p)[10] = &arr;//取出的是数组的地址
    //p应该是数组指针
    
    return 0;
}

&arr和p的类型是一致的 


三、二组数组传参的本质

二维数组的一般写法

void test(int arr[3][5],int r,int c)
{
    int i = 0;
    for (i = 0; i < r; i++)
    {
        int j = 0;
        for (j = 0; j < c; j++)
        {
            printf("%d ", arr[i][j]);
        }
    }
}


int main()
{
    int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    test(arr, 3, 5);
    return 0;
}

二维数组名是谁的地址?

根据数组名是数组⾸元素的地址这个规则

  1. 二维数组的首元素就是第一行(一维数组)
  2. 每一行都是一个元素(一维数组)

画图演示:

void test(int (*p)[5], int r, int c)
{
    int i = 0;
    for (i = 0; i < r; i++)
    {
        int j = 0;
        for (j = 0; j < c; j++)
        {
            //printf("%d ", (*p+i)[j]);
            printf("%d ", *(*(p+i)+j));// arr[i]==*(arr+i)
        }
        printf("\n");
    }
}
int main()
{
    int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    test(arr, 3, 5);
    return 0;
}

 结论:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。


四、函数指针变量

1.什么是函数指针变量?

类比:

  • 数组指针,指向数组,存放数组地址
  • 整型指针,指向整型,存放整型地址

函数指针,指向函数,存放函数的地址

int Add(int a, int b)
{
    return a + b;
}

int* test(char* s)
{
    return 0;
}
//
函数指针变量的写法和数组指针变量写法类似

int main()
{
    int*(*pt)(char) = &test;
    int arr[8] = { 0 };
    int(*pa)[8] = &arr;//pa是数组指针变量
    int (*pf)(int,int) = &Add;//pf是函数指针变量
    int x = 10;
    int y = 20;
    int z = Add(x,y);
    printf("%p\n", &Add);
    printf("%p\n", Add);


    return 0;
}

&函数名和函数名都是表示函数地址 

函数指针变量

int (*pf) (int x,int y);

解析: 

2.函数指针变量使用 

int Add(int a, int b)
{
	return a + b;
}

int main()
{
	int (*pf1)(int, int) = &Add;//pf就是函数指针变量
	int (*pf2)(int, int) = Add;

	int r1 = (*pf1)(3,7);
	int r2 = (*pf2)(3,7);//*可以
	int r4 = pf2(3,7);
	int r3 = Add(3, 7);

	printf("%d\n", r1);
	printf("%d\n", r2);
	printf("%d\n", r3);
	printf("%d\n", r4);

	return 0;
}

 3.有趣代码

代码1:

void (*p)();

int main()
{
    (*(void (*)())0)();//函数调用
    //1.将0强制类型转换成void(*)()类型的函数指针
    //2.调用0地址放的这个函数
    
    return 0;
}

 代码2

int main()
{
    void (*signal(int, void(*)(int)))(int);//函数声明
    //声明的函数名叫:signal
    //signal的函数有2个参数,第一个参数的类型是int
    //第二个参数的类型是void(*)(int)的函数指针类型,该指针可以指向一个函数,指向的函数参数是int,返回类型是void
    // signal函数的返回类型是void(*)(int)的函数指针,该指针可以指向一个函数,指向的函数参数是int,返回类型是void
    
    //void (*)(int)signal(int, void(*)(int));//err
    return 0;
}

 3.1typedef关键字

typedef对整型类型
typedef unsigned int uint;

int main()
{
    unsigned int num1;
    uint num2;
    return 0;
}


typedef对指针类型重命名
typedef int* pint;

int main()
{
    int* p1 = NULL;
    pint p2 = NULL;
    return 0;
}


数组指针重命名
typedef int(*parr_t)[5];
//*parr_t等价于int(*)[5]
int main()
{
    int arr[5] = { 10 };
    int(*p)[5] = &arr;//p是数组指针变量,p是变量的名字
    //int (*)[5] -- 数组指针类型
    parr_t p2 = &arr;
}
void test(char* s)
{

}


//对函数指针类型重命名产生新的类型pf_t
typedef void(*pf_t)(char*);

int main()
{
    void(*pf)(char*) = test;
    //void (*)(char*)
    pf_t pf2 = test;
}


五、函数指针数组

类比:

  • 字符指针数组 char* arr1[5];
  • 整型指针数组  int* arr2[5];

如果要把多个相同类型的函数指针存放在一个数组中,这个数组就叫:函数指针数组

int add(int x,int y)
{
    return x + y;

}
 
 int sub(int x,int y)
{
    return x - y;

}
int mul(int x,int y)
{
    return x * y;

}
int div(int x,int y)
{
    return x / y;
}
int main()
{
    int (*pf1)(int,int ) = add;
    int (*pf2)(int,int ) = sub;
    int (*pf3)(int,int ) = mul;
    int (*pf4)(int,int ) = div;


    int (*pfarr[4])(int, int) = { add,sub,mul,div };//pfarr就是函数指针数组
    int i = 0;
    for(i=0;i<4;i++)
    {
        int ret = pfarr[i](8,4);
        printf("%d\n", ret);
    }

    return 0;
}

int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };

解析:

 

六、转移表

我们这里写一个计算机,实现加减乘除法;

第一种写法:

int Add(int x, int y)
{
	return x + y;

}

int Sub(int x, int y)
{
	return x - y;

}

int Mul(int x, int y)
{
	return x * y;

}

int Div(int x, int y)
{
	return x / y;
}
//想写一个计算器
//完成2个整数的运行
//1.加法
//2.减法
//3.乘法
//4.除法
void menu()
{
	printf("**************************\n");
	printf("*****1.Add     2.Sub******\n");
	printf("*****3.Mul     4.Div******\n");
	printf("*****     0.exit    ******\n");
	printf("**************************\n");
	printf("**************************\n");
	printf("**************************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	do
	{
		
		menu();
		int input = 0;
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入2个操作数:");
			scanf("%d %d", &x, &y);
			ret = Add(x, y);
			printf("%d", ret);
			break;
		case 2:
			printf("请输入2个操作数:");
			scanf("%d %d", &x, &y);
			ret = Sub(x, y);
			printf("%d", ret);
			break;
		case 3:
			printf("请输入2个操作数:");
			scanf("%d %d", &x, &y);
			ret = Mul(x, y);
			printf("%d", ret);
			break;
		case 4:
			printf("请输入2个操作数:");
			scanf("%d %d", &x, &y);
			ret = Div(x, y);
			printf("%d", ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

我们可以看到选择这一部分是很冗余的,所以我们可以利用函数指针数组来解决。

第二种写法:

int Add(int x, int y)
{
	return x + y;

}

int Sub(int x, int y)
{
	return x - y;

}

int Mul(int x, int y)
{
	return x * y;

}

int Div(int x, int y)
{
	return x / y;
}
//想写一个计算器
//完成2个整数的运行
//1.加法
//2.减法
//3.乘法
//4.除法
void menu()
{
	printf("**************************\n");
	printf("*****1.Add     2.Sub******\n");
	printf("*****3.Mul     4.Div******\n");
	printf("*****     0.exit    ******\n");
	printf("**************************\n");
	printf("**************************\n");
	printf("**************************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;
	//创建一个函数指针的数组
	//转移表
	int (*pfArr[5])(int, int) = { NULL,Add,Sub,Mul,Div };
	
	do
	{
		menu();
		int input = 0;
		printf("请选择:");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			printf("请输入2个操作数:");
			scanf("%d %d", &x, &y);
			pfArr[input](x, y);
		}
		else if (input == 0)
		{
			printf("退出计算机\n");
		}
		else
		{
			printf("选择错误\n");

		}

	} while (input);
	

	return 0;
}

这一种写法就看起来清爽很多,这样也可以添加更多的功能。

我们这里可以小结一下之前所学指针:

拓展:

char*(*(*p)[4])(int,char*) = &pfArr;//取出的是函数指针数组的地址

//p就是指向函数指针数组的指针;

所以我们就有第三种写法:

int Add(int x, int y)
{
	return x + y;

}

int Sub(int x, int y)
{
	return x - y;

}

int Mul(int x, int y)
{
	return x * y;

}

int Div(int x, int y)
{
	return x / y;
}
想写一个计算器
完成2个整数的运行
1.加法
2.减法
3.乘法
4.除法
void menu()
{
	printf("**************************\n");
	printf("*****1.Add     2.Sub******\n");
	printf("*****3.Mul     4.Div******\n");
	printf("*****     0.exit    ******\n");
	printf("**************************\n");
	printf("**************************\n");
	printf("**************************\n");
}
void calu(int (*pf)(int,int))
{
	int x = 0;
	int y = 0;
	int ret = 0;
	printf("请输入2个操作数:");
	scanf("%d %d", &x, &y);
	ret = pf(x, y);
	printf("%d", ret);
}
int main()
{
	int input = 0;
	
	do
	{
		menu();
		int input = 0;
		printf("请选择:");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			calu(Add);
			break;
		case 2:
			calu(Sub);
			break;
		case 3:
			calu(Mul);
			break;
		case 4:
			calu(Div);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}

	} while (input);

	return 0;
}

第二种是将函数指针数作为跳板、第三种写法我们都是将 取出函数指针数组的地址作为跳板


总结

指针的第三节主要是字符指针变量、数组指针变量、二维数组传参的本质、函数指针变量、函数指针数组以及转移表。

标签:return,int,C语言,初见,数组,printf,函数指针,include,指针
From: https://blog.csdn.net/weixin_62408950/article/details/136782814

相关文章

  • C语言中,四则运算导致数据类型的转换
    在C语言中,四则运算可能导致数据类型的转换,这种转换称为隐式类型转换。以下是一些常见的数据类型转换情况:1.整数提升:当不同大小的整数类型(如`char`、`short`、`int`、`long`)进行混合运算时,较小的操作数会被提升为较大的类型,以便进行运算。例如,`char`类型的操作数会被提升为`......
  • C语言-教案04(从小白到劝退之运算符)
    算术运算符运算符功能说明举例+加法,一目取正a+b-减法,一目取负a-b*乘法a*b/除法a/b%取模(求余)a%b++自加1a++,++b--自减1a--,--b关注点:减号也是负号,比如-a是取变量a的相反数。取模运算要求左右两边操作数必须是整型数据......
  • 《C语言深度剖析》---------关键字(1)
    1.双击实质--->加载内存windows系统里面,双击的本质就是运行程序,把程序加载到内存里面;任何程序运行的时候都必须加载到内存里面;程序没有运行之前在硬盘里面,为什么程序运行之前必须加载到内存里面呢?这个时候就有必要了解一下冯诺依曼体系结构:我们输入的数据要到内存里面,经......
  • C语言内存函数之 memcpy和memmove函数
    memcpy函数的记忆方法:mem表示内存类函数,属于头文件string.h里面的函数。cpy是copy的缩写,表示对内存数据进行拷贝。memcpy函数的输入值和返回值:void* my_memcpy(void*brr,void*arr,size_tv) memcpy的输入值分别是被拷贝数据的brr的无类型数组的首地址,然后是拷贝给别人的无......
  • 【C语言】格式化输入/输出
    C语言格式化输入、输出简介使用printf函数格式化输出整数转换说明符浮点数转换说明符字符串转换说明符其他转换说明符字段宽度和精度控制标志转义符使用scanf函数格式化输入扫描设置(scanset)scanf函数的问题简介Streamsprovidecommunication......
  • 【C语言】文件读写
    Files&Streams访问文件顺序访问文件随机访问文件创建随机访问文件修改随机访问文件读取随机访问文件访问文件Programsmayprocessnofiles,onefileorseveralfiles.Eachfileusedinaprogrammusthaveauniquenameandwillhaveadiffe......
  • C语言解决水仙花问题
    题目叙述:水仙花数是 指一个三位数,它的每个位上的数字的3次幂之和等于它本身。(例如:153=13+53+35153=13+53+35)找到所有的水仙花数并按行打印,按从小到大的顺序输出。思路:首先确定范围,三位数(100--999),其次确定百位、十位、个位要怎么表示,令一个位数为i百位(a)a=i/100  ......
  • C语言解决切面条问题
    题目叙述:一根高筋拉面,中间切一刀,可以得到2根面条。如果先对折1次,中间切一刀,可以得到3根面条。如果连续对折2次,中间切一刀,可以得到5根面条。那么,连续对折10次,中间切一刀,会得到多少面条呢?分析:可以拿一张纸撕1条,对折3次从中间撕开是9块1次------3---2次------5---3次----......
  • C语言实现反转整数
    题目描述:从标准输入流(控制台)中获取一个整数 num,将其 按位反转 后通过输出语句输出反转后的整数,保留原来整数的正负性。思路:前提是num不等于0首先我们需要定义一个中间变量 temp 来存放当前 num 的最小位,获取最小位存在temp---temp=num%10通过 result=result*1......
  • c语言的特点
    C语言的特点可谓既鲜明又多样,下面列举几个主要的方面:简洁紧凑、灵活方便:C语言只有32个关键字,9种控制语句,程序书写形式自由,区分大小写。把高级语言的基本结构和语句与低级语言的实用性结合起来。C语言可以像汇编语言一样对位、字节和地址进行操作,而这一切又是在高级语言编译系......