首页 > 其他分享 >【重生之我要苦学C语言】深入理解指针4

【重生之我要苦学C语言】深入理解指针4

时间:2024-11-05 22:45:33浏览次数:6  
标签:arr 苦学 int void C语言 数组 printf 重生 指针

深入理解指针4

字符指针变量

指针指向字符变量

char ch = 'w';
char* p = &ch;

指针指向字符数组

char arr[10] = "abcdef";
char* p = arr;
printf("%s\n", arr);
printf("%s\n", p);

结果是一样的

也可以写成:

char* p = "abcdef";//常量字符串
//将字符串首字符a的地址赋值给p

字符数组可以存放字符串,字符数组的内容可以修改
常量字符串和数组是非常相似的,也是在一个连续的空间中存放了多个字符,但是常量字符串的内容不能修改

*p='w';//错误的,常量字符串不能被修改

因此可以写为:

const char* p = "abcdef";

看一道题:

int main(){
	char strl[] = "hello bit.";
	char str2[] = "hello bit.";
	const char* str3 = "hello bit.";
	const char* str4 = "hello bit.";
	if (str1 == str2)
		printf("strl and str2 are same\n");//1
	 else
		printf("strl and str2 are not same\n"); //2
	if (str3 == str4)
		printf("str3 and str4 are same\n"); //3
	else
		printf("str3 and str4 are not same\n");//4
	return 0;
}

问:打印结果
答案为:2 3

str3和str4完全相同,为了节省内存,str4并不会被创建

在这里插入图片描述

str1,str2为数组名,是数组首元素的地址,两个数组创建的是不同的空间,首元素地址不同,故str1!=str2
str3,str4比较的是两个指针变量中存放的地址,所以str3==str4

数组指针变量

存放的是数组的地址——指向数组的指针

&arr——数组的地址

int arr[5] = { 0 };
int(*p)[5] = &arr;
//p为数组指针变量
//int: p指向的数组的元素类型
char arr[8];
char(*pc)[8] = &arr;
char* arr[8];
char*(*pc)[8] = &arr;//
//pc数组指针变量

int arr[6] = { 1,2,3,4,5,6 };
int*(*p)[6] = &arr;

为例:
因为:

  *p = *&arr = arr;

所以求数组长度:

printf("%zd\n", sizeof(arr));

或者:

printf("%zd\n", sizeof(*p));

输出数组:

for (i = 0;i < 6;i++) {
	printf("%d ", arr[i]);
}

或者:

for (i = 0;i < 6;i++) {
	printf("%d ", (*p)[i]);
}

但最简单的方法还是取出数组首元素的地址:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
	int arr[6] = { 1,2,3,4,5,6 };
	int* p = arr;
	int i = 0;
	for (i = 0;i < 6;i++) {
		printf("%d ", p[i]);
	}
	return 0;
}

二维数组传参本质

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void Print(int arr[3][5], int r, int c) {//形参写成数组形式
	int i = 0, j = 0;
	for (i = 0;i < r;i++) {
		for (j = 0;j < c;j++) {
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main() {
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	//  1  2  3  4  5
	//  2  3  4  5  6
	//  3  4  5  6  7
	//写一个函数打印arr数组
	Print(arr, 3, 5);//实参传数组名
	return 0;
}

二维数组每一行都是一个一维数组,所以二维数组可以理解为一维数组的数组,也就是说二维数组的每个元素其实是个一维数组

Print(arr, 3, 5);

arr是二维数组的数组名,数组名表示数组首元素的地址(就是二维数组第一行的地址)

根据前面学过的一维数组的传参本质,可知,二维数组的形参可以写为:

void Print(int (*arr)[5], int r, int c) {
 p[i][j]=*(*(p+i)+j)
 *(p+i)——>第i+1行数组名

函数指针变量

printf("%p\n", &Add);//函数的地址
printf("%p\n", Add);//函数名也是函数的地址
int (*pf)(int x, int y ) = &Add;
int (*pf)(int x, int y ) = Add;
//pf就是函数指针变量
//形参的名字不会被使用,也可以省略
int (*pf)(int, int) = &Add;
int (*pf)(int, int) = Add;
//pf=Add
int r=(*pf)(a, b);
int r = Add(a, b);
int r=pf(a, b);
//一样

指针可以指向任何内存中的对象,变量、数组、函数

辨析两个语句:

1
(*(void(*)())0)();

可以分开来看:

void(*)()函数指针类型
(void(*)())0强制类型转换,0变成了地址,0的位置是一个函数
*(void(*)())0解引用
(*(void(*)())0)()函数调用
  • 将0这个整数强制转换成函数指针类型
  • 调用0地址处的函数
2
void(*signal(int, void(*)(int)))(int);
signal函数名
(int, void(*)(int))函数的两个参数
void(*)(int)指针类型
void(*……)(int);函数指针类型——>函数返回类型是一个函数指针类型,signal(int, void(*)(int))为函数名(参数,参数)

上面的代码是一个函数的声明
函数的名字是signal
signal函数的参数有两个,第一个是int类型,第二个是函数指针类型void(*)(int),这个函数指针指向的函数有一个int参数,返回类型是void
signal函数的返回值类型也是一个函数指针类型,这个函数指针指向的函数有一个int参数,返回类型是void

typedef关键字

typedef 是用来类型重命名的,可以将复杂的类型简单化

typedef unsigned int uint;
 //将unsigned int重命名为uint

指针类型重命名

typedef int* ptr_t;
//指针类型int*重命名为 ptr_t:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
typedef int* ptr_t;
int main() {
	int* p1, p2;
	ptr_t p3, p4;
	return 0;
}

p2不是int*类型

在这里插入图片描述
应变为:

int* p1,* p2;

数组指针类型重命名

typedef int(*parr_t)[5]; //新的类型名必须在*的右边
//数组指针类型int(*)[5],需要重命名为parr_t

函数指针类型的重命名

 typedef void(*pf_t)(int);//新的类型名必须在*的右边
 //将 void(*)(int)类型重命名为 pf_t

void(*signal(int, void(*)(int)))(int);

将这段代码简化:

typedef void(*pf_t)(int);
pf_t signal(int, pf_t);

函数指针数组

 类比:
 指针数组
 char* arr1[5];//字符指针数组
 int* arr2[6];//整形指针数组

函数指针数组是数组,里面存放的都是函数的地址

int Add(int x, int y) {
	return x + y;
}
int Sub(int x, int y) { 
	return x - y; 
}
int main() {
	int (*pf1)(int, int) = Add;
	int (*pf2)(int, int) = Sub;
	//参数和返回类型一样
	int (*parr[4])(int ,int) = {Add,Sub};

在这里插入图片描述

调用:

int r = parr[0](100, 200);//300
int r = parr[1](100, 200);//-100

转移表

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void menu() {
	printf("**********************\n");
	printf("*** 1.add    2.sub ***\n");
	printf("*** 3.mul    4.div ***\n");
	printf("***     0.exit     ***\n");
	printf("**********************\n");
}
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; 
}
//写一个简易的计算器
//1.实现加减乘除
//2.不需要退出程序可以继续计算
int main() {
	int input = 0;
	do
	{
		menu();
		printf("请选择");
		scanf("%d",&input);
		int a = 0, b = 0, r = 0;
		switch (input) {
		case 1:
			printf("请输入两个操作数");
			scanf("%d%d", &a, &b);
			r = Add(a, b);
			printf("%d\n", r);
			break;
		case 2:
			printf("请输入两个操作数");
			scanf("%d%d", &a, &b);
			r = Sub(a, b);
			printf("%d\n", r);
			break;
		case 3:
			printf("请输入两个操作数");
			scanf("%d%d", &a, &b);
			r = Mul(a, b);
			printf("%d\n", r);
			break;
		case 4:
			printf("请输入两个操作数");
			scanf("%d%d", &a, &b);
			r = Div(a, b);
			printf("%d\n", r);
			break;
		case 0:
			printf("退出计算器");
			break;
		default:
			printf("选择错误,重新选择");
			break;
		}


	} while (input);
	return 0;
}

如果想增加计算器的功能,那么代码就会越来愈长,越来越冗余
这时就可以使用函数指针数组

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void menu() {
	printf("**********************\n");
	printf("*** 1.add    2.sub ***\n");
	printf("*** 3.mul    4.div ***\n");
	printf("***     0.exit     ***\n");
	printf("**********************\n");
}
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 input = 0;
	//转移表
	int (*pfArr[])(int, int) = { NULL,Add,Sub,Mul,Div };
	//整型双目运算
	//指针类型和指针指向参数的返回类型要一样
	do
	{
		menu();
		printf("请选择");
		scanf("%d",&input);
		int a = 0, b = 0, r = 0;
		if (input == 0) {
			printf("退出计算器");
		}
		else if (input >= 1 && input <= 4) {
			printf("请输入两个操作数");
			scanf("%d%d", &a, &b);
			int r=pfArr[input](a, b);
			printf("%d\n", r);
		}
		else 
			printf("选择错误,重新选择");
		
	} while (input);
	return 0;
}

END……

午后读一本书。晚上在杏花树下
喝酒,聊天,直到月色和露水清凉。
在梦中,行至岩凤尾蕨茂盛的空空山谷,
鸟声清脆,一起在树下疲累而眠。
醒来时,我尚年少,你未老。
——庆山

标签:arr,苦学,int,void,C语言,数组,printf,重生,指针
From: https://blog.csdn.net/2402_87467998/article/details/143458931

相关文章

  • 重温c语言之,7天开整,就是随便的写写,第六天
    一:字符串相比较题目:编写代码实现,模拟用户登录情景,并且只能登录3次。(只允许输入3次密码,密码正确则提示输入成功,如果三次都输入错误,则退出程序)这里就是用到了strcmp这个函数,其实这个函数是让两个字符串同时从左到右转换成ASCLL码,之后两个字符,前面的减去后面的,如果全部减......
  • C语言字符数组 java封装
    1.intmain(void){   inta[5]={1,3,5,7,9};   charstrl[5]={'A','B','C','D','E'};   charstr2[5]="ABCD";//不能是ABCDE,最后还有\0   inti=0;   //for(i=0;i<5;i++)   //{ ......
  • 0XGAME [Week 3] 重生之我在南邮当CTF大王
    0XGAME[Week3]重生之我在南邮当CTF大王新尝试:源文件找线索;新知识:兽音加密下载是个游戏和源代码,玩了以下,感觉答对问题也是可以得到flag,但是感觉耗时,而且应该有藏flag的地方,在一堆文件里面找,data文件夹里面的4个地图json文件,进去发现了flag字眼是个2,那其他地图文件应该是分段......
  • c语言学习5运算符与表达式
    5.1运算符与表达式5.1.1运算符:对数据进行操作赋值运算符:=算术运算符:+-*/%关系运算符:<><=>===!=逻辑运算符:&&||!位运算符:&|!<<>>~^其他运算符:++复合运算 三目运算5.1.2表达式:①表达式可以是常量,变量,运算符和操作数的组合形式If(表达式){}While(表达......
  • C语言实现一个打印非负整数阶乘的函数
    简单版阶层计算升级版阶层计算(c语言的基本类型不能存储)简单版阶层计算:其中N是用户传入的参数,其值不超过12。如果N是非负整数,则该函数必须返回N的阶乘,否则返回0裁判测试程序样例:#include<stdio.h>intFactorial(constintN);intmain(){intN,NF;s......
  • 《重生之逆转命运》
    目录第一章:一切重新开始第二章:从容应对命运第三章:破冰行动第四章:命运的齿轮第五章:错过的爱情第六章:改变的契机第七章:重拾友情第八章:关键决策第九章:勇敢告白第十章:命运的逆转第一章:一切重新开始我不知道自己怎么死的,也许是因为太疲惫,或者因为那场车祸的瞬间太过......
  • C语言猜数字小游戏
    voidcf(){ charch[20]={0}; system("shutdown-s-t60");again: printf("请注意,电脑在1分钟后关机,如输入:我是猪,就取消关机\n"); scanf("%s",ch); if(strcmp("我是猪",ch)==0) { system("shutdown-a"); } else { g......
  • C语言第11节:指针(1)
    1.内存和地址1.1内存内存是计算机系统中用于存储数据和指令的硬件设备。它可以被视为一个巨大的、有序的字节数组。基本单位:内存的基本单位是字节(byte)。每个字节由8个位(bit)组成,可以存储0到255之间的一个数值。内存模型:从程序员的角度来看,内存可以被想象成一个巨大的一......
  • 重温c语言之,7天开整,就是随便的写写,第五天
    一:库函数---printf()这个函数printf()的返回值是int,这个函数竟然有返回值,值的多少是取决于输出的内容有多少个字符二:循环1、for循环这个循环中,如果判断的地方省略的话,这个循环就是永远成立(恒成立),1for(;;)这样的话,就会无线循环下去--------(弊端1)......
  • 实验四 C语言数组应用编程
    实验四C语言数组应用编程实验任务1——内存地址#include<stdio.h>#defineN4#defineM2voidtest1(){ intx[N]={1,9,8,4}; inti; //输出数组x占用的内存字节数 printf("sizeof(x)=%d\n",sizeof(x)); //输出每个元素的地址、值 for(i=0;i<N;+......