实验十二(指针数组进阶与结构体)

文章目录

    • A. 实验10_9_指针数组进阶
    • B. 实验10_10_动态数组进阶
    • E. 实验11_3_结构排序

A. 实验10_9_指针数组进阶

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
已知正整数n,n的范围是1—100。你要从键盘读入n个字符串,每个字符串的长度不确定,但是n个字符串的总长度不超过100000。你要利用字符指针数组将这n个字符串按照ASCII码顺序进行升序排序,然后再打印到屏幕上。字符串中可能包含ASCII码中的任意字符,每个字符串以换行符结束输入。
要求:不允许定义如char str[100][100000];这样的二维数组,因为会极大的浪费内存空间。你应定义char str[100000];这样的存储空间,将n个字符串连续的存储在一维字符空间内,然后将这n个字符串的起始位置保存在字符指针数组中,再进行排序操作。
输入与输出要求:输入一个正整数n,代表待排序字符串的个数,n不超过100,然后是n个字符串,每个字符串的长度不确定,但至少包含1个字符。n个字符串的总长度不会超过100000。输出排序后的n个字符串,每个字符串占一行。
程序运行效果:

Sample 1:

4↙
Where there is hope ,there is a way.↙
Welcome Beijing.↙
Nice idea.↙
Have fun.↙
Have fun.↙
Nice idea.↙
Welcome Beijing.↙
Where there is hope ,there is a way.↙

思路:依据提示,我的想法是:
1.首先要将许多字符串存储进一维数组。
2.是要排序。
关于1.一开始想到要用函数strcpy,或者strcat
最后发现,strcpy一复制就是全组,而strcat,虽说可以将字符数组2连接到字符数组1,但是字符数组1的\0会被吃掉,不管字符数组1有多少个\0.
(附上我的实践证明2019秋期计导实验十(数组,字符数组))
关于2.我想效仿strcmp函数的原理来进行比较,采用选择排序。
但,以上都出了问题。于是我去借鉴了其他博主的代码。
附上借鉴链接
实验十二(2018)D. 实验10_9_指针数组进阶
以下是根据大佬的代码重新理解后默写出来的AC代码

#include
#include
char Sortstr(char *strptr[],int n);
int main()
{
	char str[100000],*strptr[101],ctmstr[100000];
	int n,i;
	strptr[0]=str;//指针数组必须指向数组,接下来才能将其作为字符串名使用,进而实现输入多个字符串
	scanf("%d",&n);
	getchar();//吃掉换行符
	for(i=0;i<n;i++)
	{
		gets(strptr[i]);//输入多个字符串
		if(i!=n-1)//给出下一个字符串的起始位置
		strptr[i+1]=strptr[i]+strlen(strptr[i])+1;
	}
	Sortstr(strptr,n);//排序
	return 0;
}
char Sortstr(char *strptr[],int n)//插入排序
{
	int order[101],i,j,tmp;
	for(i=0;i<n;i++)//给辅助数组赋初值
	{
		order[i]=i;
	}
	for(i=1;i<n;i++)//插入排序:插入第i个字符串,并调整其序号
	for(j=0;j<i;j++)
	{
		//如果排序为i的字符串比排序为j的字符串小,由于j
		if(strcmp(strptr[order[i]],strptr[order[j]])<0)
		{
			tmp=order[j];
			order[j]=order[i];
			order[i]=tmp;
		}
	}
	for(i=0;i<n;i++)
	{
		puts(strptr[order[i]]);
	}
}

附上我的错误代码(仅供本人找错用,可能我以后也没有闲心找错)

#include
#include
char Sortstr(char *strptr[],int n);
int main()
{
	char str[100000],*strptr[101],ctmstr[100000];
	int n,i,len1=0,len2;
	scanf("%d",&n);
	getchar();
	strptr[0]=&str[0];
	(一)gets(str);
	for(i=1;i<n;i++)
	{
		//scanf("%s",&str[len]);
		1)gets(str[len]); 
		len=strlen(str);//不包括\0 
		if(i+1<n)
		strptr[i+1]=&str[++len];*/ 
		2)gets(ctmstr);
		len2=strlen(ctmstr);//不包括'\0'//len是ctmstr的长度,这里所求应是str加上ctmstr前的长度 
		strcat(str,ctmstr);//将str与ctmstr连起来,同我的思路1
		len1+=len2;
		strptr[i+1]=&str[len1]; 
		len1=strlen(str);
		gets(&str[++len1]);//不能这样输入字符串
	}
	(二)for(i=1;i<n+1;i++)
	{
		gets(ctmstr);
		strcpy(&str[i-1],ctmstr);//可能不能这样用 
		if(i<n)
		str[i]=str[i-1]+strlen(ctmstr)+1;
	}
	//gets(ctmstr);
	for(i=0;i<n;i++)
	printf("%s\n",strptr[i]);
	Sortstr(strptr,n);
	return 0;
}
char Sortstr(char *strptr[],int n)
{
	int i,k,j;
	char *t;
	for(i=0;i<n;i++)
	for(k=1;i+k<n;k++)//找最小字符串 
	{
		//如果指针指向的元素相等,并且其中一方没有结束,就继续找,直到其中一方结束或者两指针指向元素不等,即有大小关系 
		//for(j=0;*(strptr[i]+j)==*(strptr[i+k]+j)&&(*(strptr[i]+j)!='\0'||*(strptr[i+k]+j)!='\0');j++)
		for(j=0;*(strptr[i]+j)==*(strptr[i+k]+j)&&((strptr[i]+j)!=(strptr[i+k])||(strptr[i+k]+j)!=(strptr[i+k+1]));j++)
		{
		}
		if(*(strptr[i]+j)>*(strptr[i+k]+j)||*(strptr[i+k]+j)=='\0')//两字符串前面全部相等,长的字符串大 
		{
			t=strptr[i];strptr[i]=strptr[i+k];strptr[i+k]=t;
		}
	}
	for(i=0;i<n;i++)//验证结果
	{
		printf("*strptr[i]=%c\n",*strptr[i]);
	}
	for(i=0;i<n;i++)
	printf("%s\n",strptr[i]);
}

对了,其实一开始是想用动态数组来存这些字符串的
然而,我也不知道哪错了。
只悟出一个道理,动态数组的指针最好别乱动,别乱赋其他地址。(可是,下一题却可以直接交换地址

#include
#include
int main()
{
	int n,i;
	char **str,*t;
	scanf("%d",&n);
	getchar();
	str=(char **)malloc(sizeof(char *)*n);
	for(i=0;i<n;i++)
	str[i]=(char *)malloc(sizeof(char)*100000);//give str[i] some space
	for(i=0;i<n;i++)
	gets(str[i]);
	for(i=0;i<n;i++)
	puts(str[i]);
	for(i=0;i<n;i++)
	{
		if(strcmp(str[i],str[i+1])>0)
		{
			/*t=str[i+1];//交换地址 
			str[i+1]=str[i];
			str[i]=t;*/
			t=*(str+i+1);//和上面一个意思
			*(str+i+1)=*(str+i);
			*(str+i)=t;
		}
	}
	for(i=0;i<n;i++)
	puts(str[i]);
	return 0;
}

B. 实验10_10_动态数组进阶

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
已知正整数n,n的范围不确定。从键盘读入n个字符串,每个字符串的长度小于1000,要保存到动态数组中。为了能访问到所有的字符串,需要建立一个长度为n的动态指针数组,用于保存n个字符数组的内存地址。在读入每个字符串时,用一个长度为1000的字符数组作为缓冲数组,将字符串读入并求出长度后,再动态分配空间,将缓冲数组中的字符串复制到新分配的动态空间中,并将动态空间的首地址保存到指针数组中。读完n个字符串后你要将这n个字符串按照ASCII码顺序升序排序,然后再打印到屏幕上。字符串中可能包含大小写字母“A-Z”、“a—z”与空格字符。每个字符串以换行符结束输入。
输入与输出要求:输入一个正整数n,代表待排序字符串的个数。然后输入n个字符串,每个字符串至少包含一个字符,占一行。输出排序后的n个字符串,每个字符串占一行。
程序运行效果:

Sample 1:
10↙
Bb b↙
zzz zzz↙
aab bbccc↙
aaabbaaa↙
abb bbb↙
ccidfjD↙
Aidj idj↙
Ccidf jD↙
sidfjijE EE↙
kkkkkk↙
Aidj idj
Bb b
Ccidf jD
aaabbaaa
aab bbccc
abb bbb
ccidfjD
kkkkkk
sidfjijE EE
zzz zzz

这题思路简单,按着题意走就是。我直接就着动态指针数组开辟了字符串的存储空间,而有一种做法是:
另外定义一个动态数组,然后将其首地址保存在指针数组里,并且,排序时采用冒泡排序,交换的是地址。这种做法之所以能成,我认为是,同一个指针变量每次动态得到的内存空间不一样。
实验十二(指针数组进阶与结构体)_第1张图片

#include
#include
#include
#define SIZE 1001 
void Sortstr(char **a,int n);
int main()
{
	int n,i;//n个字符串 //
	scanf("%d",&n);
	char **a,cushion[SIZE];
	a=malloc(sizeof(char *)*n);
	getchar();
	for(i=0;i<n;i++)
	{
		gets(cushion);
		a[i]=malloc(sizeof(char)*(strlen(cushion)+1));
		strcpy(a[i],cushion);
	}
	Sortstr(a,n);
	/*for(i=0;i
	return 0;
}
void Sortstr(char **a,int n)	
{
	int i,j;
	//char cushion[SIZE];
	char *t; 
	for(i=1;i<n;i++)
	for(j=0;j<i;j++)//插入排序
	{
		if(strcmp(a[i],a[j])<0)
		{
			//交换值会出问题 ,cushion较大,而,a[i],a[j]都是大小限定了的 
			/*strcpy(cushion,a[j]);
			strcpy(a[j],a[i]);
			strcpy(a[i],cushion);*/
			//竟然真的可以交换地址?
			t=a[j];
			a[j]=a[i];
			a[i]=t;
		}
	}
	for(i=0;i<n;i++)
	{
		puts(a[i]);
	}
}

然而该代码所占内存空间和运行时间都很大(忽略那个运行时错误)
最后发现,好像大家都很大,可能是数据本身就这么大吧
在这里插入图片描述

E. 实验11_3_结构排序

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
有n名学生,每个学生的属性包括姓名与总成绩。已知学生的姓名与总成绩,你的任务是将学生的信息按照以下方式排序:首先比较总成绩,总成绩高的在前面,总成绩低的在后面,当总成绩相同时,你要比较学生的姓名,姓名字典序小的同学在前面,姓名字典序大的同学在后面(ASCII码顺序)。n的范围是1—100;学生的姓名中只能包含大小写字母,不会超过20个字符;总成绩为整数。
要求:在本题中,你要设计一个结构来存储学生的信息。在此结构中,需要有一个字符数组来存储姓名,一个整型变量存储总成绩。
输入与输出要求:首先输入一个正整数n,代表学生的数量,1<=n<=100;每名学生的信息按照姓名、总成绩的顺序输入(空格分开),每名学生信息占一行。输出:n名学生的信息,姓名占一行,总成绩占一行,输出顺序要按照题目的要求,每名同学的信息后都再输出一个空行。输入具体格式见样例。

输入样例
4
AlbertEinstein 1328
GeorgeWalkerBush 860
LiuMengmeng 1475
BillGates 1328
输出样例
Name:LiuMengmeng
total:1475

Name:AlbertEinstein
total:1328

Name:BillGates
total:1328

Name:GeorgeWalkerBush
total:860

结构体的应用,粘这一个就够了吧
这题的难点在于将结构体按份数排序并且原来结构体对应名字的分数不能改变。
我采用新定义一个辅助数组order,用于记录第几个输出的结构体的标号。排序时只需将分数最小的结构体的标号冒到最后就行。
以下是AC代码。

#include
struct student{
	char name[21];
	int score;
};
int main()
{
	struct student stu[101];
	//struct student *ptr=&stu;
	int n,temp,i,j,k,order[101];
	scanf("%d",&n);	
	for(i=0;i<n;i++)
	order[i]=i;
	for(k=0;k<n;k++)
	{
	//	getchar();
		scanf("%s",stu[k].name);
		scanf("%d",&stu[k].score);
	}
	for(i=0;i<n;i++)
		for(j=0;j<n-i-1;j++)//将分数最小的结构体的标号冒到最后
		{
			if(stu[order[j]].score<stu[order[j+1]].score)
			{
				temp=order[j];
				order[j]=order[j+1];
				order[j+1]=temp;
			}
			if(stu[order[j]].score==stu[order[j+1]].score)
			{
				if(strcmp(stu[order[j]].name,stu[order[j+1]].name)>0)//将字典序大的标号排到后面
				{
					temp=order[j];
					order[j]=order[j+1];
					order[j+1]=temp;
				}
			}
		}
	for(k=0;k<n;k++)
	{
		printf("Name:%s\ntotal:%d\n\n",stu[order[k]].name,stu[order[k]].score);
	}
	return 0;
}

事实证明,我还是渣渣本渣,写这些题(前面的指针)有点费劲了。

你可能感兴趣的:(计导C语言+计算机一些知识)