2019秋期计导实验十一(关于指针)

A. 实验9_8_设计函数 void delcharfun(char *str,char ch)

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
问题描述:
设计函数 void delcharfun(char *str,char ch)实现从字符串str中删除指定的字符ch。同一字母的大、小写按不同字符处理。
输入与输出要求:
输入一个长度不超过100的非空字符串与一个字符,代表需要处理的字符串与需要从字符串中删除的字符。其中字符串中不会出现空格、换行符。输出删除指定字符以后的字符串,占一行。如果删除指定字符后字符串变为空串,则直接输出空行。

输入样例
abcABCabc#
b
输出样例
acABCac#

考察指针的应用。思路是,将数组作为首地址传给指针后直接用指针访问元素,从而实现删减元素。
以下是AC代码

#include<stdio.h>
#include<string.h>

void delcharfun(char *str,char ch)
{
	int i,j,k,t=0;
	for(i=0,j=i;*(str+i)!='\0';i++,j++)
	{
		if(*(str+i)==ch)//对于一大长串相连的相等的字符串,这个判断有问题。**一种办法,把它赋成空指针,在输出上做文章;另一种,删除后全部往前移,从0开始找** 
		//这里采用第二种
		{
			while(*(str+j)!='\0')
			{
				*(str+j)=*(str+j+1),j++;
				//printf("j=%d ",j);	
			}
			i=-1;
			j=i;//如果不将i,j赋成-1这里到循环最后又会加成1!!!
			//下一次判断就会跳过第0个元素从而造成下图所示结果	
		}
		/*printf("i=%d,j=%d\n",i,j);
		for(k=0;*(str+k)!='\0';k++)
		printf("%c ",*(str+k));
		if(*(str+k)=='\0')printf("\n");	*/ 
	}
	//while(*(str+i)!='\0')printf("*(str+i)=%c\n",*(str+i));//无输出//说明循环是='\0 '之后才停的 
}
int main()
{
	char a[101],ch;
	gets(a);
	scanf("%c",&ch);
	delcharfun(a,ch);
	puts(a);
	return 0;
}

(不将i,j赋成-1的结果)
在这里插入图片描述
关于假想的第一种方法的验证,好像不能直接赋成空指针。
在这里插入图片描述
(试验程序)在这里插入图片描述
在这里插入图片描述
(左值应该是变量,而不是表达式)

#include<stdio.h>
#include<string.h>
#define SIZE 501
char *eqchar(char *str1,char *str2);
char *locatesubstr(char *str1,char *str2,int len)
{
	int i,j=0,num=0;
	//先把条件想好

	for(j=0;*str1!='\0';j++,i=0)//每次循环i赋成0重新开始 
	{
		while(*(str1+i)==*(str2+i)&&*(str2+i)!='\0')
		{
			num++;
			//str1++;
			i++;
			if(num==len)return str1;
		}
		//if(*(str2+i)!='\0')
		 
			str1=str1+i;//如果没有找到相等的那节,保留现有的进度 
			num=0;//重新计数 
			str1=eqchar(str1,str2);//寻找下一个相等的开头 
			//str1--;
			//printf("%d\n",str1);
		
	}
	//while(*(str1+i)!='\0'&&*(str1+i)!=*(str2+j))//i,j要不一样 
	
	//else if(*str1!='\0')*locatesubstr(str1,str2,len);
	return NULL;
	//printf("%s\n",str1);
	//return str1;
}
char *eqchar(char *str1,char *str2)//用于寻找与str2第一个元素相等的指针 
{
	while(*str1!='\0'&&*str1!=*str2) 
	{
		str1++;
	}
	return str1;
}
int main()
{
	char str1[SIZE],str2[SIZE];
	int len;
	gets(str1);
	gets(str2);
	len=strlen(str2);
	if(locatesubstr(str1,str2,len))
	printf("%s\n",locatesubstr(str1,str2,len));
	else printf("NULL!\n");
	//printf("%s\n",str1);
	return 0;
}

B. 实验10_4_设计函数char *locatesubstr

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
设计函数 char *locatesubstr(char *str1,char *str2),查找str2指向的字符串在str1指向的字符串中首次出现的位置,返回指向该位置的指针。若str2指向的字符串不包含在str1指向的字符串中,则返回空指针NULL。
注意这里必须使用指针而不是数组下标来访问字符串。
输入与输出要求:输入两个长度不超过500的非空字符串str1和str2,字符串中可能出现空格,以换行符结束。输出str1中返回指针后的所有字符;否则输出“NULL!”。
程序运行效果:

Sample 1:
didjfsd dabcxxxxxx↙
abc↙
abcxxxxxx
Sample 2:
aaaaabcaaa↙
xxx↙
NULL!
哈哈哈,先让我大笑三声,终于找出bug来了。快落。
在这里插入图片描述
这题思路很简单:找到str1与str2相同的的元素,验证接下来是不是也相同,若相同则返回str1,不相同则返回NULL.
我写了两个代码,主干部分相同,第一个却怎么也过不了,写了第二个之后才发现问题。
先贴上第一个代码(改过后的):
先说说它的特点,将寻找与str2相等的str1的地址用另一个函数来求,出发点是好的,但是,这题不必要,具体请看第二种。
错误之处在于[1],保留现有进度什么鬼,如果出现这种例子呢:str1:aabcgggg
str2:abc
按照之前的代码,这种输出NULL!显然是错的。

#include<stdio.h>
#include<string.h>
#define SIZE 501
char *eqchar(char *str1,char *str2);
char *locatesubstr(char *str1,char *str2)
{
	int i,j=0;
	while(*str1!='\0') 
	{
		while(*(str1+i)==*(str2+i)&&*(str2+i)!='\0')
		{
			i++;
		}
		if(*(str2+i)=='\0') return str1;
		else 
		{
			/*str1=str1+i;//如果没有找到相等的那节,保留现有的进度 */[1]
			str1++;
			str1=eqchar(str1,str2);//寻找下一个相等的开头 
		}
		i=0;
	}
	return 0;
}
char *eqchar(char *str1,char *str2)//用于寻找与str2第一个元素相等的指针 
{
	while(*str1!='\0'&&*str1!=*str2) 
	{
		str1++;
	}//不管是因为=='\0 停止的还是相等停止的,返回去,for 会重新判断 
	//if(*str1!='\0')
	return str1;
	//else return NULL;//如果直到str1结束也没找到相等的,返回空指针 //不必要 
}
int main()
{
	char str1[SIZE],str2[SIZE];
	int len;
	gets(str1);
	gets(str2);
	//len=strlen(str2);
	if(locatesubstr(str1,str2))
	printf("%s\n",locatesubstr(str1,str2));
	else printf("NULL!\n");
	//printf("%s\n",str1);
	return 0;
}

第二个代码,

#include<stdio.h>
#include<stdlib.h>
char *locatesubstr(char *,char *);
int main()
{
	char str1[501],str2[501];
	gets(str1);
	gets(str2);
	if(locatesubstr(str1,str2))
	printf("%s\n",locatesubstr(str1,str2));
	else printf("NULL!");
	return 0;
}
char *locatesubstr(char *str1,char *str2)
{
	while(*str1!='\0')
	{
		int i;
		if(*str1==*str2)//找到相等点
		{
			for(i=0;*(str1+i)==*(str2+i)&&*(str2+i)!='\0';i++)
			{
			}//不需要有语句,满足条件i就继续加1,直到不满足
			if(*(str2+i)=='\0')return str1;
			//如果是因为str2结束导致的跳出循环,说明已经找到了
			else str1++;
		}
		else str1++;//如果不相等,则下一个继续比较,直到找到相等的,进入if
	}
	return NULL;
}

C. 实验10_5_指针数组初步

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
已知一个总长度不超过10000的字符串,字符串中只包含大写字母“A—Z”、小写字母“a—z”和空格‘ ’。空格用于分割单词,空格的个数不超过1000个。你的任务是将字符串中用空格分隔的单词打印出来。
你要按照如下要求完成任务:
1.利用指针数组指向每个单词的开始位置。
2.把字符串中单词结束后的空格改为“\0”,然后使用指针数组将每个单词打印出来。
3.不可直接输出或使用二维数组输出单词。
输入与输出要求:输入一个字符串,满足题目描述,占一行。输出这个字符串中的单词,每个单词占一行。
程序运行效果:

Sample 1:
You are great↙
You↙
are↙
great↙
Sample 2:
itisalongword↙
itisalongword↙

这题不难,思路是寻找空格,改成’\0’即可,难的是,如何将使用指针数组表示出来。
以下是AC代码

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int i,j;
	char a[10001],**aptr;
	gets(a);
	aptr=malloc(sizeof(char *)*1002);//定义了指针数组包含的指针数
	*aptr=a;//将aptr内的第一个指针指向数组a首地址,等价于aptr[0]=a[0]; 
	for(i=0,j=1;*(a+i)!='\0';i++)
	{
		if(*(a+i)==' ')//如果a[i]==空格 
		{
			*(a+i)='\0';
			aptr[j]=a+i+1;	
			j++;
		}
	}
	//for(i=0;*aptr+i!=0;i++)//这个条件好像没用 //没有将指针数组初始化为NULL 不能这样写 
	for(i=0;i<j;i++)
	//puts(*aptr+i);//意思是,在范围j内,移动指针数组首指针,//不符合要求 
	printf("%s\n",aptr[i]);
	free(aptr); 
	return 0;
}

E. 实验10_7_动态分配内存_2(动态指针数组)

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
已知正整数n、m,你要利用malloc函数动态开辟一个n行、m列的整型二维数组,然后读取nm个整数存入该数组中。再将这nm个整数全部改为其相反数的10倍,然后将其输出。最后你要利用free函数将该动态数组所占用的空间释放。
**
提示:malloc与free的使用,以下代码即建立了一个n行m列的整型二维动态数组,并释放:
int * *a,n ,m;
scanf(“%d%d”,&n,&m);
a=(int * *)malloc(sizeof(int *)*n);//建立长度为n的动态指针数组
for(i=0;i<n;i++)
a[i]=(int *)malloc(sizeof(int)*m);//建立长度为m的一维整型数组
for(i=0;i<n;i++)
free(a[i]);
free(a);//释放动态内存
**

输入为两行,第一行为两个用空格分隔的正整数n,m,第二行为nm个用空格分隔整数。测试用例保证所有整数可以用int存储,且为这nm个整数申请内存不会超出内存限制。
输出按矩阵格式输出,具体见样例。

输入样例
3 4
1 2 3 4 5 6 7 8 9 10 11 12
输出样例
-10 -20 -30 -40
-50 -60 -70 -80
-90 -100 -110 -120

过此题的三种姿势(嘿嘿)
主要是指针与数组的三种表示方式:
1.申请完内存后,直接用数组,如下

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int n,**a,i,m,j;
	scanf("%d%d",&n,&m);
	a=(int **)malloc(sizeof(int *)*n);
	for(i=0;i<n;i++)
	a[i]=(int *)malloc(sizeof(int)*m);
	
	for(i=0;i<n;i++)
	for(j=0;j<m;j++)
	{
		scanf("%d",&a[i][j]);
		a[i][j]=10*a[i][j]*(-1);
	}
	
	for(i=0;i<n;i++)
	{
	for(j=0;j<m;j++)
	{
		printf("%d ",a[i][j]);
	}
	printf("\n");
	}
	for(i=0;i<n;i++)
		free(a[i]);
	free(a);
	return 0;
}

2.指针加数组,混合式

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int n,**a,i,m,j;
	scanf("%d%d",&n,&m);
	a=(int **)malloc(sizeof(int *)*n);
	for(i=0;i<n;i++)
	a[i]=(int *)malloc(sizeof(int)*m);
	
	for(i=0;i<n;i++)
	for(j=0;j<m;j++)
	{
		scanf("%d",a[i]+j);//a[i]+j是地址,故不用取地址符
		*(a[i]+j)=10*(*(a[i]+j))*(-1);
		
	}
	
	for(i=0;i<n;i++)
	{
	for(j=0;j<m;j++)
	{
		printf("%d ",*(a[i]+j));
	}
	printf("\n");
	}
	for(i=0;i<n;i++)
		free(a[i]);
	free(a);
	return 0;
}

3.全指针,这里要说一下,之前用* a+i+j,傻兮兮的以为指向后申请的一维数组的指针 * a可以先移动到i行,再移动到j列
事实上,可以用指向 * a的指针a,先移动到i行,然后再移动到j列,像这样 * (a+i)+j.

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int n,**a,i,m,j;
	scanf("%d%d",&n,&m);
	a=(int **)malloc(sizeof(int *)*n);
	for(i=0;i<n;i++)
	a[i]=(int *)malloc(sizeof(int)*m);
	
	for(i=0;i<n;i++)
	for(j=0;j<m;j++)
	{
		scanf("%d",*(a+i)+j);
		*(*(a+i)+j)=10*(*(*(a+i)+j))*(-1);
	}
	
	for(i=0;i<n;i++)
	{
	for(j=0;j<m;j++)
	{
		printf("%d ",*(*(a+i)+j));
	}
	printf("\n");
	}
	for(i=0;i<n;i++)
		free(a[i]);
	free(a);
	return 0;
}

F. 实验7_21_编码、解码数组(重点看看解码)

运行时间限制: 1000 运行内存限制: 65536
作者: scshuanghai 是否specialjudge: False
题目描述
设有一个整型数组a中存放n个互不相同的整数,a中元素取值范围为0到n-1。a数组的编码定义如下:a[0]的编码为0,放入b[0];ai的编码为在a[0]、a[1]、…、a[i-1]中比a[i]的值小的数的个数,放入b[i]。例如:a[6]={4,3,0,5,1,2}时,则b[6]={0,0,0,3,1,2}。你有两个任务,任务一是编码,即已知n与数组a,求数组b;任务二是解码,即已知n与数组b,求数组a。
输入与输出要求:首先输入两个整数n和flag。n代表数组元素的个数(1<=n<=100),flag代表任务类型(flag=1代表编码任务,flag=2代表解码任务)。然后是n个整数,当flag=1时,这n个数即代表数组a的内容;当flag=2时,这n个数即代表数组b的内容。
输出n个整数,当flag=1时即为编码后数组b的内容,当flag=2时,即为解码后数组a的内容。每个整数用空格分开,最后一个整数后是换行符。
程序运行效果:
Sample 1:
5↙
1↙
2 1 3 0 4↙
0 0 2 0 4
Sample 2:
8↙
2↙
0 1 2 0 1 1 4 5↙
3 6 7 0 2 1 4 5

这题编码部分好想,就是解码比较难一点。
说说思路
编码只需要统计前面有多少数比本数大,用数组b存下来就行;
解码:寻找一般普适的规律,可以这样想,有另外一个数组num,存着按升序排列的0,1,2,3…n-1,我们要做的只是把其中的数按照b数组给出的信息,将它存在a数组中。b数组给了什么信息呢?
从后开始排,在num中数字保持升序的情况下,你会发现,b数组中的数字就是它在num数组中的下标。
在这里插入图片描述
以下是完全AC的代码,做几点说明:
1.用函数分别写编码与解码,便于找错
2.因为学的是指针,强迫着用了指针写,编码中*(a+i)等同于a[i],

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void encode(int);
void decode(int);
int main()
{
	int n,flag;
	scanf("%d%d",&n,&flag);
	if(flag==1)
	encode(n);
	else decode(n);
	return 0;
}
void encode(int n)
{
	int *a,*b,i,j;
	a=malloc(sizeof(int)*n);//动态申请a,b数组,元素个数为n个 
	b=malloc(sizeof(int)*n);
	for(i=0;i<n;i++)
	scanf("%d",a+i);
	memset(b,0,n*sizeof(int));//将数组b清0 
	for(i=1;i<n;i++)
	for(j=0;j<i;j++)
	{
		if(*(a+j)<*(a+i))
		b[i]++;//记录正序数 
	}
	for(i=0;i<n;i++)
	printf("%d ",*(b+i));//输出数组b 
	printf("\n");
}
void decode(int n)//具体说明见思路
{
	int num[101]={0},i,j,k,b[101],a[101];
	for(i=0;i<n;i++)
	scanf("%d",&b[i]);
	for(i=0;i<n-1;i++)
	num[i+1]=num[i]+1;
	for(i=n-1;i>=0;i--)
	{
		a[i]=num[b[i]];
		for(j=b[i];j<n-1;j++)
		num[j]=num[j+1];
	} 
	for(i=0;i<n;i++)
	printf("%d ",a[i]);
	printf("\n");
}

以下是第一次写时,思路搞错了写的。
错误思路为,b数组中元素含义为a数组中对应元素要移到的位置。即,将*(a+i)插入到*(a+*(b+i))所指的位置上,且不改变其他元素位置。
除了定义时,之后在程序中看到它们就是这些意思
在这里插入图片描述

void decode(int n)
{
	int **a,*b,i,j,*t;
	b=malloc(sizeof(int)*n);
	a=(int **)malloc(sizeof(int *)*n);
	for(i=0;i<n;i++)
	{
		a[i]=(int *)malloc(sizeof(int)*1);//建立长度为1的一维数组; 
	} 
	for(i=0;i<n;i++)//给数组赋初值 
	**(a+i)=i;
	for(i=0;i<n;i++)
	{
		scanf("%d",b+i);
		t=*(a+i);//将指向i位置数字的指针赋给t指针
		for(j=i;j>*(b+i);j--)
		{
			*(a+j)=*(a+j-1);//将*(a+*(b+i))之后的指针往后移,此时*(a+i)储存的地址被更改 
		}
		
		*(a+*(b+i))=t;//将之前保存的*(a+i)指向的地址赋给*(a+*(b+i)),实现将*(a+i)插入到*(a+*(b+i))上 
		for(j=0;j<n;j++)
		printf("%d ",**(a+j));
		printf("\n");
	}
	for(i=0;i<n;i++)
	printf("%d ",**(a+i));
	printf("\n");
} 

结果及过程如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值