当前位置: 首页 > news >正文

C程序设计(第5版)——谭浩强(2)

参考:https://blog.csdn.net/qq_50696399/article/details/141574823

ch8 指针

在对程序进行编译时,系统会给变量分配内存单元。(int分配4个字节,float分配4个字节,char分配1个字节)。内存区中的每一个字节有一个编号,称为地址
地址指向变量单元,

地址 = 指针

C语言的地址包括位置信息(内存编号,或称纯地址)和它所指向的数据的类型信息,或者说它是带类型的地址

int i;
编译时,系统为变量i分配了4个字节的内存单元,建立了变量名地址的对应表。
printf(“%d\n”,i);
通过变量名找到相应的地址,从该4个字节中按照整型数据的存储方式读出i的值。

直接访问:通过变量名找到对应的值;
间接访问:变量名对应的地址放在指针变量,通过地址找到对应的值;

//例8.1
int main()
{
	int a = 100, b = 10;
	int * p1 = &a, * p2 = &b;
	printf("a = %d b = %d", *p1, *p2);
	return 0;
}

//例8.2
int main()
{
	int a,b;
	int *p = &a, *q = &b;
	scanf("%d %d", p, q);
	if (*p >= *q)
		printf("%d", *p);
	else
		printf("%d", *q);
	return 0;
}

//例8.3
int main()
{
	void swap(int* p, int* q);
	int a,b;
	int *p = &a, *q = &b;
	scanf("%d %d", p, q);
	if (*p <= *q)
		swap(p, q);
	printf("max = %d, min = %d\n", a, b);
	return 0;
}
void swap(int* p, int* q)//直接改了地址所指向的内容,如果是形参在改,上面的值不会变
{
	int t = *p;
	*p = *q;
	*q = t;
}
//例8.4
void swap(int* p, int* q)//直接改了地址所指向的内容,如果是形参在改,上面的值不会变
{
	int* t = p;
	p = q;
	q = t;
}

//例8.5
int main()
{
	void exchange(int* p, int* q, int* r);
	void swap(int* p, int* q);
	int a, b, c;
	int *p = &a, *q = &b, *r = &c;
	scanf("%d %d %d", p, q, r);
	exchange(p, q, r);
	printf("max = %d, mid = %d, min = %d\n", a, b, c);
	return 0;
}
void swap(int* p, int* q)//直接改了地址所指向的内容,如果是形参在改,上面的值不会变
{
	int t = *p;
	*p = *q;
	*q = t;
}
void exchange(int* p, int* q, int* r)
{
	if (*p < *q)//确保*p最大
		swap(p, q);
	if (*p < *r)//确保*p最大
		swap(p, r);
	if (*q < *r)//确保*q第二最大
		swap(q, r);
}

指针变量p
p+1不是将p的值简单加1,而是p的值加指针类型所占用的字节数
指针变量p1和p2都指向同一数组的元素时,p2-p1的结果是两个地址差再除以数组元素长度

//例8.6
int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	for (int i = 0; i < 10; i++)
		printf("%d ", a[i]);
	return 0;
}
int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	for (int i = 0; i < 10; i++)
		printf("%d ", *(a+i));//a是元素首地址,地址是指针,指针+i不是简单地加i
	return 0;
}
int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 }, *p = a;
	for (; p < a+10; p++)//p址是指针,指针+i不是简单地加i
		printf("%d ", *p);
	return 0;
}

//例8.7
int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 }, *p = a;
	for (int i = 0; i < 10;i++, p++)//p址是指针,指针+i不是简单地加i
		printf("%d ", *p);
	return 0;
}

//例8.8
int main()
{
	void inv(int* x, int n);
	int a[10] = {3,7,9,11,0,6,7,5,4,3 }, *p = a;
	inv(a, 10);
	for (; p < a + 10; p++)//p址是指针,指针+i不是简单地加i
		printf("%d ", *p);
	return 0;
}
void inv(int* x, int n)
{
	int* len = x + n / 2;
	int* y = x + n - 1;//指向尾
	for (; x < len; x++, y--)
	{
		int t = *x;
		*x = *y;
		*y = t;
	}
}

//例8.10
int main()
{
	void sort(int* x, int n);
	int a[10] = {12,34,5,689,-43,56,-21,0,24,65}, *p = a;
	sort(a, 10);
	for (; p < a + 10; p++)//p址是指针,指针+i不是简单地加i
		printf("%d ", *p);
	return 0;
}
void sort(int* x, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int max_val = *(x + i), max_ind = i, t;
		for (int j = i + 1; j < n; j++)
			if (*(x + j) > max_val)
			{
				max_val = *(x + j);
				max_ind = j;
			}
		t = *(x + max_ind);
		*(x + max_ind) = *(x + i);
		*(x + i) = t;
	}
}

通过指针引用多维数组

int a[3][4];

a是二维数组名;a数组包含3个元素a[0],a[1],a[2];
a[0]是一维数组名,a[0]数组包含4个元素a[0][0],a[0][1],a[2][0],a[0][3];
a是二维数组,a[0]是一维数组,a[0]是数组的数组,这是二维数组的角度。

数组名是首元素地址
a含义:a二维数组的元素是每一行,首元素地址是第0行地址,值为&a[0],a指向a[0]
a+1含义:第1行地址,值为&a[1],a+1指向a[1]
a[0]含义:a[0]一维数组的元素是第0行的每一列,首元素地址是第0行 第0列地址,值为&a[0][0],a[0]指向a[0][0]
a[1]含义:第1行第0列地址,值为&a[1][0],a[1]指向a[1][0]
a[0]+1不是简单地加1,a[0]是地址,加的是a[0]类型的字节数;
a[0]+1含义:第0行第1个元素地址,值为&a[0][1],a[0]+1指向a[0][1]
a指向一维数组a[0],a[0]指向列元素a[0][0]。对不同的指针进行加1运算,得到的结果是不同的。

书本原文:从二维数组的角度来看,a代表二维数组首元素的址,现在的首元素不是一个简单的整型元素,而是由4个整型元素组成的一维数组,因此a代表的是首行的起始地址。如果二维数组的首行的起始地址为2000,a+1的值应该是2000+4*4=2016。(一行4个元素,每个元素4个字节)

重要:a[0]和*(a+0)等价;a[i]和*(a+i)等价;
则a[0]+1和*(a+0)+1的值都是&a[0][1];
a[1]+2和*(a+1)+2的值都是&a[1][2]
如果a是二维数组,则a[i]是一维数组名,它只是一个地址,并不是一个存储单元,进而也不是存储单元中的值。

得到地址后在地址前面再加一个解引用得到这个地址所指的值,即(a[0]+1)和*(*(a+0)+1)的值都是a[0][1]

在这里插入图片描述

说明:C语言的地址信息包含位置信息和指向数据的类型信息。a[0]是一维数组名,a是二维数组名,二者地址相同,但指向类型不同,一个指向整型数据,一个指向一维数组。用指针变量pt指向这个一维数组,应当这样定义:
int (*pt)[4];
pt指向类型:由4个int元素组成的一维数组;
对比int *p;
p指向类型:一个int元素
简单粗暴的理解:
假设p指向一维数组,那么定义pt时后面多了个[4],说明pt指向二维数组;
星p就是a[0]的值,星(星(pt+i) + j)就是a[i][j]的值

//例8.12
int main()
{
	int a[3][4] = { 1,3,5,7,9,11,13,15,17,19,21,23 }, *p = a;
	//p<a+12以a的行元素个数来加,地址的取值上为:a+(12*4*4)
	//含义分别为:12为要加12次,4为一个int占4字节地址,4为一行4个元素
	//要循环12*4次,因为p++每次只走一个元素的地址长度,而非一行的地址长度
	//正常循环12次,地址的取值上为:a+(12*4)
	for (p = a; p < a[0] + 12; p++)
	{
		printf("%d ", *p);
	}
	return 0;
}

//例8.13
int main()
{
	int a[3][4] = { 1,3,5,7,9,11,13,15,17,19,21,23 }, (*p)[4] = a;
	//p指向由4个int元素组成的一维数组
	//*p指向由4个int元素组成的一维数组的第0个int
	//*(p)+1为0行1列的地址,*(p+2)+1为2行1列的地址
	//现在是a+3而不是a[0]+12,共有3行,大循环3次,p++每加一次地址加的是一行4个int元素的字节数(4*4)=16
	for (p = a; p < a + 3; p++)
	{
		for (int i = 0; i < 4; i++)//小循环4次
			printf("%d ", *(*(p) + i));
		printf("\n");
	}
	return 0;
}

//例8.14
int main()
{
	void average(float* p, int n);
	void search(float (*p)[4], int n);
	float score[3][4] = { 65,67,70,60,80,87,90,81,90,99,100,98 };
	average(*score, 12);//score是首元素地址,首元素为一行float;*score是首元素地址,首元素为此行的一个float
	search(score, 2);//score是首元素地址,首元素为一行float
	return 0;
}
void average(float* p, int n)
{
	float* p_end = p + n, ave = 0;
	for (; p < p_end; p++)
	{
		ave += (*p) / 12;
	}
	printf("ave = %f\n", ave);
}
//*p指向一维数组,指向类型为一个float
//(*p)[4]指向二维数组,指向类型为一行float,p是首元素地址,p是数组名
void search(float (*p)[4], int n)
{
	for (int i = 0; i < 4; i++)
	{
		printf("%f ", *(*(p+n)+i));
	}
}

//例8.15
int main()
{
	void search(float (*p)[4], int n);
	float score[3][4] = {65,67,70,60,58,87,90,81,90,99,100,98};
	search(score, 3);//(*p)[4]指向类型为4个float组成的数组
	return 0;
}
void search(float (*p)[4], int n)
{
	for (int i = 0; i < n; i++)
	{
		bool flag = true;
		for (int j = 0;j < 4; j++)
		{
			if (*(*(p+i)+j) < 60)
			{
				flag = false;
			}
		}
		if(!flag)
			for (int j = 0; j < 4; j++)
				printf("%f ", *(*(p + i) + j));
		printf("\n");
	}
}

//例8.17
int main()
{
	//字符串实际为字符数组,有一个虚无的数组名,数组名是首元素地址赋给了string
	char* string = "I love you";
	printf("%s\n", string);
	return 0;
}

//例8.18
int main()
{
	char* a = "I love you", b[20];
	int i = 0;
	for (; *(a+i) != '\0'; i++)
		b[i] = a[i];
	b[i] = '\0';
	for (int i = 0; *(b + i) != '\0'; i++)
	{
		printf("%c", b[i]);
	}
		
	return 0;
}

//例8.19
int main()
{
	char* a = "I love you", b[20], *p1 = a, *p2 = b;
	for (; *p1 != '\0'; p1++, p2++)
		*p2 = *p1;
	*p2 = '\0';
	for (int i = 0; *(b + i) != '\0'; i++)
	{
		printf("%c", b[i]);
	}	
	return 0;
}

//例8.20
int main()
{
	void copy_string(char* from, char* to);
	char* a = "teacher", b[] = "student", *from = a, *to = b;
	copy_string(from, to);
	printf("%s\n%s", a,b);
	return 0;
}
void copy_string(char* from, char* to)
{
	for (; *from!='\0'; from++,to++)
	{
		*to = *from;
	}
	*to = '\0';
}

指向函数的指针
函数名就是函数的指针,它代表函数的起始地址
定义:
int (*p)(int, int);指针p指向类型为有两个int参数的函数
int (*p)[4];指向类型为4个int组成的数组
int *p;指向类型为一个int元素
使用:(*p)看成函数名完事

//例8.23
int main()
{
	int find_max(int x, int y);
	int find_min(int x, int y);
	int (*p)(int, int) = find_max;//定义指针变量p,它指向find_max的首地址
	int (*q)(int, int) = find_min;
	int a, b, choose;
	scanf("%d %d %d", &a, &b, &choose);
	if(choose == 1)
		printf("max = %d", (*p)(a, b));
	else if(choose == 2)
		printf("min = %d", (*q)(a, b));
	return 0;
}
int find_max(int x, int y)
{
	if (x >= y)
		return x;
	else
		return y;
}
int find_min(int x, int y)
{
	if (x <= y)
		return x;
	else
		return y;
}

//例8.24
int main()
{
	int fun(int x, int y, int(*p)(int, int));
	int find_max(int x, int y);
	int find_min(int x, int y);
	int add(int x, int y);
	int a = 34, b = -21, choose;
	scanf("%d", &choose);
	if(choose == 1)
		printf("max = %d", fun(a,b, find_max));
	else if(choose == 2)
		printf("min = %d", fun(a, b, find_min));
	else if (choose == 3)
		printf("sum = %d", fun(a, b, add));
	return 0;
}
int fun(int x, int y, int(*p)(int, int))
{
	return (*p)(x, y);
}
int find_max(int x, int y)
{
	if (x >= y)
		return x;
	else
		return y;
}
int find_min(int x, int y)
{
	if (x <= y)
		return x;
	else
		return y;
}
int add(int x, int y)
{
	return x + y;
}

返回指针值的函数
int *a(int x, int y);
理解:标题的名词是函数,a(int x, int y)是一个函数,返回类型为int星

//例8.25
int main()
{
	float score[][4] = { 60,70,80,90,56,89,67,88,34,78,90,66 };
	float* search(float (*p)[4], int n), p;
	int n;
	scanf("%d", &n);
	for (int i = 0; i < 4; i++)
		printf("%5.2f\t", *(search(score, n)+i));
	
	return 0;
}
float* search(float (*p)[4], int n)//返回第n个学生第0门成绩的地址
{
	return *(p + n);//p是行地址,+n加到了第n行地址,再*解引用得到n行0列地址
}

//例8.26
int main()
{
	float score[][4] = { 60,70,80,90,56,89,67,88,34,78,90,66 };
	float* search(float (*p)[4]);
	for (int i = 0; i < 3; i++)
	{
		if (search(score + i))
		{ 
			printf("No:%d\n", i);
			for (int j = 0; j < 4; j++)
				printf("%f ", *(search(score + i) + j));
			printf("\n");
		}
	}
	return 0;
}
float* search(float (*p)[4])//p指向类型为1行float
{
	for (int i = 0; i < 4; i++)
	{
		if (*(*p + i) < 60)//当前行i列的值
			return *p;//返回当前行i列的地址
	}
	return NULL;
}

指针数组:int* p[4]
理解:p[4]定义一个数组,这个数组类型为int*
对比:int (*p)[4];
理解:用星p定义一个 指针变量p,它指向类型为4个int

//例8.27
int main()
{
	void sort(char* name[], int n);
	char* name[] = { "Follow me","BASIC","Great Wall","FORTRAN","Computer design" };
	sort(name, 5);
	for (int i = 0; i < 5; i++)
	{
		printf("%s\n", name[i]);
	}
	return 0;
}

void sort(char* name[], int n)
{
	for(int i =0;i<n-1;i++)//每排序一个数要一个大循环
		for (int j = i + 1; j < n; j++)//排这个数要从剩下的数中找更小的
		{
			if (strcmp(name[j], name[i]) < 0)
			{ 
				char* t = name[j];
				name[j] = name[i];
				name[i] = t;
			}
		}
}

//例8.28
int main()
{
	void sort(char* name[], int n);
	char* name[] = { "Follow me","BASIC","Great Wall","FORTRAN","Computer design" };
	char** p;//指针的指针,name已经是存放指针的一个东西了,再多一个*就指向name
	for (int i = 0; i < 5; i++)
	{
		p = name + i;//p指向name,name+i指向name的第i个元素,
		printf("%s\n", *p);//解引用得到第i个元素的值,就是第i个字符串的地址
	}
	return 0;
}

//例8.29
int main()
{
	int a[5] = { 1,3,5,7,9 };
	char* num[5] = { &a[0],&a[1] ,&a[2] ,&a[3] ,&a[4] };
	char** p = num;
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", **p++);//先**P,再p++
	}
	return 0;
}

动态内存分配与指向它的指针变量
全局变量分配在内存的静态存储区;(静态区)
局部变量分配在内存的动态存储区;(栈stack区)
C语言可以动态分配内存,随时弃用;(堆heap区)

void* malloc(unsigned int size);
函数名为malloc,返回类型为指针,指针指向类型为void;
功能:开辟1个长度为size的连续空间

void* calloc(unsigned, unsigned int size);
函数名为calloc,返回类型为指针,指针指向类型为void;
功能:开辟n个长度为size的连续空间

void* realloc(void 星p, unsigned int size);
函数名为realloc,返回类型为指针,指针指向类型为void;
功能:改p指向的内存空间大小为size,成功返回p,不成功返回空指针NULL

void free(void* p)
功能:释放p指向的动态空间

使用:int 星p = (int星)malloc(100);
解释:int *p定义指针变量p,指向类型为int,指向一个动态空间,指针变量的值为动态空间的首地址
malloc函数返回的是void星类型,不能直接引用;强制转换成int星方便引用

//例8.30
int main()
{
	void check(int* p);
	int* p = (int*)malloc(5 * sizeof(int));
	//p[5] = { 67, 98,59,78,57 };//不合法;
	p[0] = 67; p[1] = 98; p[2] = 59; p[3] = 78; p[4] = 57;
	check(p);
	return 0;
}
void check(int *p)
{
	for (int *p_end = p + 5; p < p_end; p++)
		if (*p < 60)
			printf("%d ", *p);
}

一个指针包含3个信息:
1、他是指针类型
2、它的指向类型
3、指针变量的值(地址)
指针是地址,指针变量的值是地址
在这里插入图片描述

习题8

//1.2.
int main()
{
	void sort_num(int* p);
	void sort_str(char (*p)[4]);
	int num[3] = { 9,3,6 };
	char str[][4] = {"abc", "abb", "aaa"};
	sort_num(num);
	printf("%d %d %d", num[0], num[1], num[2]);
	sort_str(str);
	printf("\n%s\n%s\n%s\n", str[0], str[1], str[2]);
	return 0;
}
void sort_num(int* p)//p指向num的首元素
{
	int t;
	if (*p > *(p + 1))//最小的放第0位
	{
		t = *p; *p = *(p + 1); *(p + 1) = t;
	}
	if (*p > *(p + 2))//最小的放第0位
	{ 
		t = *p; *p = *(p + 2); *(p + 2) = t;
	}
	if (*(p + 1) > *(p + 2))//次小的放第1位
	{
		t = *(p + 1); *(p + 1) = *(p + 2); *(p + 2) = t;
	}
}
void sort_str(char (*p)[4])//选择法排序
{
	char t[4];
	for(int i = 0; i < 2; i++)
		for(int j = i + 1; j < 3; j++)
			if (strcmp(*(p + i), *(p + j)) > 0)//*(p + i)=p[i]=i行0列地址=第i行数组的首地址=第i个字符串名
			{
				strcpy(t, p[i]);
				strcpy(p[i], p[j]);
				strcpy(p[j], t);
			}
}

//3.
int main()
{
	void input(int* p);
	void sort(int* p);
	void output(int* p);
	int num[10], *p = num;
	input(p);
	sort(p);
	output(p);
	return 0;
}
void input(int* p)
{
	printf("输入10个数\n");
	for (int* p_end = p + 10; p < p_end; p++)
		scanf("%d", p);
}
void sort(int* p)
{
	int t;
	for (int i = 1; i < 10 ;i++)
	{
		if (*p > *(p + i))
		{
			t = *p;
			*p = *(p + i);
			*(p + i) = t;
		}
	}
	for (int i = 0; i < 9; i++)
	{
		if (*(p + 9) < *(p + i))
		{
			t = *(p + 9);
			*(p + 9) = *(p + i);
			*(p + i) = t;
		}
	}
}
void output(int* p)
{
	printf("输出10个数\n");
	for (int* p_end = p + 10; p < p_end; p++)
		printf("%d ", *p);
}

//4.
int main()
{
	void move(int* p, int m, int n);
	int num[10] = {1,3,5,7,9,0,2,4,6,8}, * p = num;
	move(p, 3, 10);
	for (int i = 0; i < 10; i++)
		printf("%d ", num[i]);
	return 0;
}
void move(int* p, int m, int n)
{
	for (int i = 0; i < m; i++)//移动m个数
	{
		int t = *(p + n -1);
		for (int j = n - 2; j >= 0; j--)
		{
			*(p + j + 1) = *(p + j);
		}
		*p = t;
	}
}

//6.
int main() {
	int str_len(char* str);
	char str[] = "I love you.", * p = str;
	printf("字符串长度为%d\n", str_len(str) );
	return 0;
}
int str_len(char* str)
{
	return strlen(str);
}

//7.
int main() {
	char* str_copy(char* str, int m);
	char str[] = "I LOve you.520**", * p = str;
	printf("%s\n", str_copy(p, 3));
	return 0;
}

char* str_copy(char* str, int m)
{
	char* str2 = (char*)malloc((strlen(str + m) + 1) * sizeof(char));
	strcpy(str2, str + m);
	return str2;
}

//8.
int main() {
	char str[] = "I LOve you.520**", * p = str;
	int big = 0, small = 0, space = 0, num = 0, other = 0;
	for (int i = 0; i < strlen(str); i++, p++)
	{
		if (*p >= 'A' && *p <= 'Z')
			big++;
		else if (*p >= 'a' && *p <= 'z')
			small++;
		else if (*p >= '0' && *p <= '9')
			num++;
		else if (*p == ' ')
			space++;
		else
			other++;
	}
	printf("big = %d, small = %d, num = %d, space = %d, other = %d, ", big, small, num, space, other);
	return 0;
}

//9.
int main() {
	void trasn(int (*p)[3]);
	int num[][3] = {1,3,5,7,9,0,2,4,6}, (*p)[3] = num;
	printf("Orignal:\n");
	for(int i = 0;i < 3; i++)
	{ 
		for (int j = 0;j < 3;j++)
		{
			printf("%d\t", num[i][j]);
		}
		printf("\n");
	}
	trasn(num);
	printf("trasn:\n");
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			printf("%d\t", num[i][j]);
		}
		printf("\n");
	}
	return 0;
}
void trasn(int (*p)[3])
{
	for (int i = 0; i < 3; i++)
	{
		int t;
		for (int j = i; j < 3; j++)
		{
			t = p[i][j];
			p[i][j] = p[j][i];
			p[j][i] = t;
		}
	}
}

//11.
int main() 
{
	void sort(char (*p)[3]);
	char str[10][3] = { "dd","xx", "zz","aa", "tt","yy", "gg","ff", "ww","qq" };
	sort(str);
	for (int i = 0; i < 10; i++)
	{
		printf("%s\n", str[i]);

	}
	return 0;
}

void sort(char (*p)[3])
{
	for(int i = 0;i < 9; i++)
	{ 
		char* t = (char*)malloc(3);
		for (int j = i + 1; j < 10; j++)
		{
			if (strcmp(*(p + i), *(p + j)) > 0)
			{
				strcpy(t, *(p + i));
				strcpy(*(p + i), *(p + j));
				strcpy(*(p + j), t);
			}
		}
	}
}

//12.
int main() 
{
	void sort(char (*p)[10]);
	char str[10][10] = { "ers","xc", "weqr","joa", "afvds","cxz", "hgeruy","aacas", "ab","babf" };
	sort(str);
	for (int i = 0; i < 10; i++)
	{
		printf("%s\n", str[i]);

	}
	return 0;
}

void sort(char (*p)[10])
{
	for(int i = 0;i < 9; i++)
	{ 
		char* t = (char*)malloc(10);
		for (int j = i + 1; j < 10; j++)
		{
			if (strcmp(*(p + i), *(p + j)) > 0)
			{
				strcpy(t, *(p + i));
				strcpy(*(p + i), *(p + j));
				strcpy(*(p + j), t);
			}
		}
	}
}

//14.
int main() 
{
	void sort(int* p);
	int num[5] = { 1,2,3,4,5 };
	sort(num);
	for (int i = 0; i < 5; i++)
	{
		printf("%d\n", num[i]);

	}
	return 0;
}
void sort(int* p)
{
	int t;
	for(int i = 0;i < 5 / 2; i++)
	{ 
		t = p[i];
		p[i] = p[4 - i];
		p[4 - i] = t;
	}
}

//15.
int main() 
{
	void f1(int(*p)[5]);
	void f2(int(*p)[5]);
	void f3(int(*p)[5]);
	float a[4][5] = { 90,99,92,94,90,88,86,58,98,40,90,89,87,85,85,67,55,60,51,67 }, i, j, * p = &a[0][0];

	f1(a);
	f2(a);
	f3(a);
	return 0;
}
void f1(float(*p)[5])
{
	float ave = 0;
	for(int i = 0;i < 4; i++)
	{ 
		ave += *(*(p + i)) / 4;
	}
	printf("第1门平均分:%f\n", ave);
}
void f2(float(*p)[5])
{
	for (int i = 0; i < 4; i++)
	{
		int flag = 0;
		for (int j = 0; j < 5; j++)
		{
			if (*(*(p + i) + j) < 60)
				flag++;
		}
		if (flag >= 2)
		{
			printf("学号:%d\n", i);
			printf("全部课程成绩:%f %f %f %f %f\n", *(*(p + i) + 0), *(*(p + i) + 1), *(*(p + i) + 2), *(*(p + i) + 3), *(*(p + i) + 4));
			printf("平均成绩:%f\n", (*(*(p + i) + 0)+ *(*(p + i) + 1)+ *(*(p + i) + 2)+ *(*(p + i) + 3)+ *(*(p + i) + 4) ) / 5);
		}
	}
}
void f3(float(*p)[5])
{
	for (int i = 0; i < 4; i++)
	{
		float ave = 0;
		bool flag = true;
		for (int j = 0; j < 5; j++)
		{
			ave += *(*(p + i) + j) / 5;
		}
		if (ave >= 90)
		{
			printf("平均成绩90以上学号:%d\n", i);
		}
		for (int j = 0; j < 5; j++)
		{
			if (*(*(p + i) + j) < 85)
				flag = false;
		}
		if (flag)
		{
			printf("全部成绩85以上学号:%d\n", i);
		}
	}
}

//16.
int main() 
{
	void f(char* p);
	float a[4][5] = { 90,99,92,94,90,88,86,58,98,40,90,89,87,85,85,67,55,60,51,67 }, i, j, * p = &a[0][0];
	char* str = "A123x456 17960? 302tab5876";
	f(str);

	return 0;
}
void f(char* p)
{
	char t[10];
	int a[5];
	bool num_flag = 0;
	for (int i = 0, j = 0, k = 0; p[i] != '\0'; i++)
		if (p[i] >= '0' && p[i] <= '9')
		{
			t[j++] = p[i];
			if(p[i+1] < '0' || p[i + 1] > '9' || p[i + 1] == '\0')
			{
				t[j] = '\0';
				a[k++] = atoi(t);
				j = 0;
			}
		}
	for (int i = 0; i < 5; i++)
		printf("%d\n", a[i]);
}

//17.
int main() 
{
	int strcmp_diy(char* p1, char* p2);
	char str1[] = "BOY";
	char str2[] = "BOYY";
	printf("%d\n", strcmp_diy(str1, str2));
	return 0;
}
int strcmp_diy(char *p1, char *p2)
{
	int i = 0;
	for (; p1[i] != '\0' && p2[i] != '\0'; i++)
	{
		if (p1[i] > p2[i])
			return 1;
		if (p1[i] < p2[i])
			return -1;
		if (p1[i] == p2[i])
			continue;
	}
	if (p1[i] == '\0' && p2[i] == '\0')
		return 0;
	else if (p1[i] == '\0')//前面一样,但是p1短
		return -1;
	else if (p2[i] == '\0')//前面一样,但是p2短
		return 1;
}

//18.
int main() 
{
	int n;
	char month[13][20] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }, *p[13];
	for (int i = 0; i < 13; i++)
	{
		p[i] = month[i];//i行0列地址给指针数组
	}
	scanf("%d", &n);
	printf("%s\n", p[n]);
	return 0;
}

//19.
int main() 
{
	char* new(int n);
	char* p = new(2);
	p[0] = 'B'; p[1] = 'B';
	printf("%c %c %c\n", *p, *(p + 1), *(p + 2));//*(p + 2)为没开辟存储空间时的值
	free(p);
	printf("%c %c\n", *p, *(p + 1));//释放后指向这两个地方的值恢复成 没开辟存储空间时的值
	return 0;
}

//20.
int main() 
{
	void sort(char** p);
	char str[][10] = {"abcd", "aaa", "abbbb", "acde", "aabb"}, * p[5];
	for (int i = 0; i < 5; i++)
		p[i] = str[i];
	char** q = &p;
	sort(q);
	for (int i = 0; i < 5; i++)
	{
		printf("%s\n", *(q+i));
	}
	return 0;
}
void sort(char** p)//p是指针的指针,*p是指针,指针是地址,*p是地址,是字符串首元素地址,是字符串名
{
	for (int i = 0; i < 4; i++)
	{
		char t[10];
		for(int j = 0; j < 4 - i; j++)
			if (strcmp(*(p + j), *(p + j + 1)) > 0)//*(p+j)是第j个字符串名
			{
				strcpy(t, *(p + j));
				strcpy(*(p + j), *(p + j + 1));
				strcpy(*(p + j + 1), t);
			}
	}
}

//21.
int main() 
{
	void sort(int** p, int n);
	int n;
	printf("input n:\n"); 
	scanf("%d", &n);
	int* p = (int*)malloc(n * sizeof(int));
	printf("input n numbers:\n");
	for (int i = 0; i < n; i++)
		scanf("%d", &p[i]);
	int** q = &p;
	sort(q, n);
	printf("Sorted:\n");
	for (int i = 0; i < n; i++)
	{
		printf("%d ", p[i]);
	}
	return 0;
}
void sort(int** p, int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		int t;
		for(int j = 0; j < n - 1 - i; j++)
			if ((*p)[j] > (*p)[j + 1])
			{
				t = (*p)[j];
				(*p)[j] = (*p)[j + 1];
				(*p)[j + 1] = t;
			}
	}
}

相关文章:

  • 构建简单RAG代码实现
  • java常见面试场景题
  • nodejs各版本下载地址 —— 筑梦之路
  • 【Java】泛型与集合篇 —— 泛型
  • virt-io 如何运行在 kvm windows 虚拟机上
  • rust学习三、基本类型
  • Spring框架基本使用(Maven详解)
  • 【二分搜索 C/C++】洛谷 P1873 EKO / 砍树
  • SAM C++ TensorRT(实时图像分割)
  • 【有啥问啥】DeepSeek 技术原理详解
  • vue取消全选功能按钮注意事项
  • java机器学习计算指标动态阈值
  • Jackson使用
  • 点击unity资源文件自动展开左侧的文件路径
  • StableDiffusion学习笔记——4、模型下载和学习
  • 算法系列之搜索算法-广度优先搜索BFS
  • 提示工程(Prompt Engineering)的进阶策略与实践指南
  • 关于uniApp的面试题及其答案解析
  • 【Python】yield函数
  • 遥感与GIS在滑坡、泥石流风险普查中的实践技术应用
  • 旭辉控股集团:去年收入477.89亿元,长远计划逐步向轻资产业务模式转型
  • 马克思主义理论研究教学名师系列访谈|丁晓强:马克思主义学者要更关注社会现实的需要
  • 车展之战:国产狂飙、外资反扑、智驾变辅助
  • 山西太原一处居民小区发生爆炸,现场产生大量浓烟
  • 辽宁辽阳市白塔区一饭店火灾事故举行新闻发布会,现场为遇难者默哀
  • 移动互联网未成年人模式正式发布