C语言实验过程化记录-1

        之前在学校学C语言指针部分的时候,看到了这样一道题:

编写程序 ,程序实现的功能是:假设有 20 个英文姓名,将姓名按升序排序。        

        最开始那会儿还没有什么思路,在网上搜索了一下相同题的解题思路,只看到了有个百度知道里的回答。回答里的思路很好,不过感觉上和指针关系不是很大。因此博主决定自行尝试编写本程序。

        首先整理一下思路,将姓名由小到大排序,还要用上指针,我们可以:

  1.        设置一个二维数组,让二维数组的每行空间存储一个名字。
  2.        设置一个数组指针,提前将名字定义在数组指针内部。
  3.        设置一个结构体存放名字。

        之后设置一个函数,使用冒泡法,将名字按字母大小重新排序。

        前面列出的3个分支方法其实都只是在收集名字上有些许差别。本文重点分析第一种思路,后两种简单介绍。

目录

二维数组法

1. 纠正理解strcpy

2. 冒泡法强化记忆

数组指针法

结构体法

1. qsort函数

(1)功能

(2)函数声明 

without qsort


二维数组法

        第一种思路的主函数如下:

int main()
{
	int i = 0;
	char name[20][10];
	printf("请输入20个英文名字:\n");
	for (i = 0; i < 20; i++)
	{
		scanf("%s", name[i]);
	}
	my_bubble(name);
	printf("\n******************\n//排序后的结果为//\n");
	for (i = 0; i < 20; i++)
	{
		printf("%s\t", name[i]);
	}
	printf("\n******************\n");
	return 0;
}

这里二维数组name在输入输出时使用的name[i],意思是第i行上name数组里的数据。比如说用户输入了“Tom \n Peter \n”,那么在name数组里前两行存储的就是

  • “         T        o        m        \0        \0        \0        \0        \0        \0        \0 "
  • "         P        e        t          e          r         \0        \0        \0        \0        \0 "

冒泡法函数如下:

void my_bubble(char name[][10])
{
	int i = 0;
	int j = 0;
	char tmp[20] = { 0 };
	//char* p = tmp;//_!通过每次循环最后指针指向NULL,实现内存清空
	for (i = 0; i < 20; i++)//循环的总次数
	{
		for (j = 0; j < (19 - i); j++)//每次循环要比较的元素数量
		{
			if (strcmp(name[j], name[j+1])== 1)//交换
			{
				strcpy(tmp, name[j]);
				strcpy(name[j], name[j + 1]);
				strcpy(name[j + 1], tmp);
				//p = NULL;//_!
			}
		}
	}
}

1. 纠正理解strcpy

这段里我保留下的//_!两排注释主要是记录当时自己的错误理解(那两段注释是不对的),纠正自己之前对strcpy的一些误解。

之前已经知道strcpy具有溢出隐患,曾经以为strcpy是通过将后一段字符串直接挤在前一段字符串开头实现的。但实际上,strcpy是通过将后一段字符串覆盖前一段字符串数据实现的。

举个例子说明下我的错误理解和实际情况:

char a[20] = "umbrella";
	char b[5] = "rain";
	strcpy(a, b);
	puts(a);

我理解在strcpy后,a数组里的情况是:r a i n \n u m b r e l l a \n

而事实上,strcpy会覆盖原数组的数据:r a i n \n l l a \n (umbre被覆盖掉了)

再说strcpy的隐患是什么。就原先代码举例,当我们想把a的字符串覆盖在b里时,由于b里只有5个char的内存,分配的内存不足以存放”umbrella"字符串,所以存在溢出问题。

//这段代码最后会崩溃
char a[20] = "umbrella";
	char b[5] = "rain";
	strcpy(b, a);
	puts(b);
	return 0;

2. 冒泡法强化记忆

冒泡法很常见,理解了就能用。

for( i = 0; i <sz ; i++)

// 确定了比较次数,这里要遍历数组里的所有元素,比较次数就是所有元素的总数

        for( j = 0; j< (sz - 1 - i) ; j++)

        //确定每次要拿来比较的两个数,不断一次3左右两个比较

        {

                if (a[ j ] > a[ j + 1] )

                //这里使用升序,要从小到大

                设置一个中间变量,交换两个元素。

        }


数组指针法

首先提一句,不能用指针数组啊,一般指针数组都会把常值给定义出来,比如char* arr[ 2 ] = { "harry" , "poter" } ; 这里面的两个元素都不能被改变,到后面要用冒泡法交换两个内容的位置就很麻烦了。

数组指针法其实比较多此一举,写出来主要是为了让自己以后更好地理解并应用数组指针。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
void my_cmp(char(*np)[10])
{
	int i = 0;
	int j = 0;
	char tmp[20] = { 0 };
	for (i = 0; i < 20; i++)//冒泡法实现姓名排序
	{
		for (j = 0; j < (19 - i); j++)
		{
			if (strcmp(*(np + j), *(np + j + 1)) == 1)
			{
				strcpy(tmp, *(np + j));
				strcpy(*(np + j), *(np + j + 1));
				strcpy(*(np + j + 1), tmp);
			}
		}
	}
}
int main()
{
	int i = 0;
	char name[20][10];
	char(*np)[10] = &name;
	printf("请输入20个英文名字:\n");
	for (i = 0; i < 20; i++)
	{
		scanf("%s",name[i]);
	}
	my_cmp(np);
	printf("//排序后的结果为//\n");
	for (i = 0; i < 20; i++)
	{
		printf("%s	",name[i]);
	}
	return 0;
}

结果如下图:

­


结构体法

结构体法里我使用了最近学的函数——qsort函数。对这个函数,我在这里简单介绍一下。

1. qsort函数

(1)功能

        对所指数组元素进行升序或逆序排序。C语言里要调用头文件stdlib.c

(2)函数声明 

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))

 就像本实验程序里写的:

        qsort ( people,  sz,  sizeof ( people [ 0 ] ),  name_cmp ) ;

第一个空要填需要排序的数组中的首元素地址。第二个空要填数组长度。第三个空要填每个元素所占内存的大小,第四个空填写一个比较两元素大小的函数。

接着再进入这个函数里,简要解释一下“((struct member*)e1)->name”是什么意思:

(struct member*)指的是参数类型是结构体指针,e1里存放着结构体某个name的地址,然后(struct member*)e1整体指向了成员name,将其解引用得到e1地址里存放的name数据。

注意,由于e1,e2是两个地址,所以获取结构体成员数据时要用" -> ",不能用“ . ”。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct member {
	char name[10];
}people[20];//定义结构体

int cmp_str(const void* e1, const void* e2)//sqrt内部实现前后排序的函数
{
	return strcmp(((struct member*)e1)->name, ((struct member*)e2)->name);
}

int main()
{
	int i = 0, j = 0;
	int sz = sizeof(people) / sizeof(people[0]);
	printf("请输入20个英文名字:\n");
	for (i = 0; i < 20; i++)
	{
		scanf("%s", people[i].name);
	}
	qsort(people, sz, sizeof(people[0]), cmp_str);//使用qsort函数进行排序
	printf("///排序后的结果为///\n");
	for (i = 0; i < 20; i++)
	{
		printf("%s	", people[i].name);
		j++;
		if(j==4)
		{
			printf("\n");
			j = 0;
		}
	}
	return 0;
}

without qsort

当然不用qsort函数也可以做出来,我把只用了结构体的代码也截取了部分下来。

void bubble_sort(int sz, struct member p[])
{
	int i = 0;
	int j = 0;
	char tmp1[10] = { 0 };
	for (i = 0; i < sz; i++)
	{
		for (j = 0; j < (sz - 1 - i); j++)
		{
			if (strcmp(p[j].name, p[j + 1].name) == 1)
			{
				strcpy(tmp1, p[j].name);
				strcpy(p[j].name, p[j+1].name);
				strcpy(p[j + 1].name, tmp1);
			}
		}
	}
}
int main()
{
	int i = 0, j = 0;
	int sz = sizeof(people) / sizeof(people[0]);
	printf("请输入20个英文名字:\n");
	for (i = 0; i < 20; i++)
	{
		scanf("%s", people[i].name);
	}
	bubble_sort(sz, people);
	printf("///排序后的结果为///\n");
	for (i = 0; i < 20; i++)
	{
		printf("%s	", people[i].name);
		j++;
		if(j==4)
		{
			printf("\n");
			j = 0;
		}
	}
	return 0;
}

最后结果为

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值