C的回归基础练习篇1

C的回归基础练习篇1

前言

因为一次通宵后整个人这周一直不大聪明的亚子,疯狂的补微积分和工图,完全忘记了还有c,现在开始疯狂补回来。

基础の三道小题

  1. 题目
    编程实现:用户给定一个整数,将该整数逆置之后输出。(如:输入123,输出321)。a.给定整数,不要用字符串来完成。b.尽可能使时间复杂度小。c.要求能够完成214748364792这个数字的逆置。
    分析
    看到逆置首先想到字符串的逆置函数strrev(),很明显出题人也想到了,所以只能老老实实用取模和除法来做,至于复杂度肯定是O(n)没得说,就是常数问题小常数不用管,大常数管不了,嘿嘿。因为没有告知整数位数,所以while伺候(好像我上次才说了while没多大用)。最后记得开longlong完事儿。
    代码
#include <cstdio>
#include <cstdlib>
int main()
{
	long long num,newNum=0ll;
	int temp;
	scanf("%lld",&num);
	while(num)
	{
		temp=num%10;
		newNum=newNum*10+temp;
		num/=10;
		printf("%lld\n",newNum);
	}
	printf("%lld\n",newNum);
	return 0;
 } 
  1. 题目:编程实现:给定一串任意字符串(如:1023fase415#145#)要求,将其中的所有整数提取出来并存入整数数组(例子中的是{1023, 415, 145}三个)。
    分析:还是有关字符串转换整数的题,乖乖模拟就行啦,也没有什么细节好说。
    代码
#include<cstdio>
#define N 10010
using namespace std; 
char ch[N];
int temp,results[N],p=0;
bool check(int i)//检查ch[]第i位是否是数字字符 
{
	return (ch[i]<='9'&&ch[i]>='0') ? true : false;
}
int pickUp(int i)//提取以i位为起始的数字,并返回数字末位的后一位 
{
	temp=0;
	while(check(i)) 
	{
		temp=temp*10+(int(ch[i++])-'0');
	}
	
	results[p++]=temp;
	return i;
} 
int main()
{
	scanf("%s",ch);
	int i=0; 
	while(ch[i]!='\0')
	{
		if(check(i)) 
		{
			i=pickUp(i);
		}
		else i++;
	}
	for(i=0;i<p;i++)
	printf("%d ",results[i]);
	return 0;
 } 
  1. 题目:编程实现:给定一串任意字符串(如:10.23fase4.15#14.5#)要求,将其中的所有数字提取出来并存入double数组(例子中的是{10.23, 4.15, 14.5}三个)。
    分析:与上一题一样模拟,就是有一点特殊情况,比如asd0.dsa9.1sad8k可以提取出0.0,9.1,8.0,不过一般代码也不会出错的。另外cv大法好?
    代码
#include<cstdio>
#define N 10010
using namespace std; 
char ch[N];
double temp1,temp2,t=0.1,results[N];
int p=0;
bool check(int i)//检查ch[]第i位是否是数字字符 
{
	return (ch[i]<='9'&&ch[i]>='0') ? true : false;
}
int pickUp(int i)//提取以i位为起始的数字,并返回数字末位的后一位 
{
	temp1=0.0;
	temp2=0.0;
	t=1.0;
	while(check(i)) 
	{
		temp1=temp1*10.0+(int(ch[i++])-'0');
	}
	if(ch[i]=='.')
	{
		i++;
		while(check(i))
		{
			t*=0.1;
			temp2+=(int(ch[i++])-'0')*t;
		}
	}
	results[p++]=temp1+temp2;
	return i;
} 
int main()
{
	scanf("%s",ch);
	int i=0; 
	while(ch[i]!='\0')
	{
		if(check(i)) 
		{
			i=pickUp(i);
		}
		else i++;
	}
	for(i=0;i<p;i++)
	printf("%lf ",results[i]);
	return 0;
 } 

提高の一些代码理解

  1. 代码
#include <stdio.h>
int main()
{
	char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
	char** cp[] = { c + 3, c + 2, c + 1, c };
	char*** cpp = cp;
	printf("%s\n", **++cpp);
	printf("%s\n", *--*++cpp + 3);
	printf("%s\n", *cpp[-2] + 3);
	printf("%s\n", cpp[-1][-1] + 1);
	system("pause");
	return 0;
	//禁止套娃!!!
}

结果

POINT
ER
ST
EW

分析
首先说下,那个system(“pause”)的函数库没有声明啊

  1. 初始化解释:char* c[]我理解的是定义了一个一维的字符串数组,或者说是指针数组,数组中每个元素都是char*(应该可以看成字符串)的指针;char** cp[]={}是定义了一个指针数组,数组中每个元素都是char** 的指针,其实就是char*** 类型;而这就刚好是cpp的类型。所以从某种意义上讲cpp就是cp,只是cp是一个常量指针,不能自加或自减。
  2. 输出分析
  • printf("%s",**++cpp); ++cpp是指cp+1, * (cp+1)是cp[1]=c+2,** (cp+1)=*(c+2)=‘POINT’
  • printf("%s",*--*++cpp + 3); ++最优先,所以++cpp=cp+2; * ++cpp=* (cp+2)=c+1; --(c+1)=c; *(c+1)=“ENTER”; 最后的+3是因为c是一个char 类型的指针,所以+3表示(c+1)代表的字符串的第三位后面字母即“ER”
  • printf("%s",*cpp[-2]+3) ;注意此时cpp=cp+2,所以cpp[-2]=* (cpp-2)=* (cp+2-2)=* cp (=cp[0]) =c+3,再+3与上同理。
  • printf("%s",cpp[-1][-1]+1); 注意[]不改变cpp的值,所以cpp=cp+2; 先算前面一个[-1],所以cpp[-1]=* (cpp-1)=* (cp+2-1)= * (cp+1)=c+2; 再来一个[-1]得:(c+2)[-1]=* (c+2-1)=* (c+1)=“NEW”; 再+1同上上。
    题外话
    这个东西太打脑阔了,我看这个看了一晚上都不是很懂,讲道理真的有人会几个指针夹着[]符号用吗?
  1. 代码
#include <stdio.h>
struct Test
{
	int Num;
	char *pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
int main()
{
	p = 0x100000;
	printf("%p\n", p + 0x1);
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0;
}
//结果
0x100020
0x100001
0x100004

分析:首先不知道为什么,这个代码在我的Devc++上编译会失败,错还有两处。但其实这个代码比上一个简单,认真思考和查阅后就可以理解。最后在网上找到了这题的结果,虽有小不同但大体上还是差不多。

  • 首先0x100000是一个地址,而0x1是十六进制下的1
  • 公式:p+n 的地址值 =(p)+n*sizeof(p)
  • 通过sizeof(Test)=32可得Test占32个字节,则第一个输出是则是(p)+1*32=0x100020
  • 第二个就是把p强制转换成一个unsigned long型的数,所以按照加法运算可以得0+1=1(当然是十六进制下的)
  • 第二个就是把p强制转换成一个unsigned int,变成一个指向int的指针,所以(p)+1*sizeof(unsigned int)=0x100004
  1. 代码
#include <stdio.h>
int main()
{
	int a[4] = { 1, 2, 3, 4 };
	int *ptr1 = (int *)(&a + 1);
	int *ptr2 = (int *)((int)a + 1);
	printf("%x\n%x\n", ptr1[-1], *ptr2);
	return 0;
}
//输出结果如下:
0x4
0x2000000

分析:我不知道是不是我编译器的问题,这个代码还是无法编译。
不过这次找到了问题,因为在我的编译器中(我的电脑是64位)int与long同占4字节,而指针是占8字节,故会出现:loses precision。我在网上看到别人把int改为long就可以了,但我的需要改为long long。这样上面一道题的也照样子改了改也可以运行。所以这告诉我们:“当你解决不了某一问题时,放下他,时间 咕咕咕 会解决一切问题”(手动滑稽)

  • 当a前面有&操作符时,编译器将会把a对应符号表中的地址看作指向数组的指针,所以第一个初始化实际上是加了一个数组的大小,让ptr1指向了a[4]的地址,所以输出ptr1[-1]=* (ptr1-1)=* (a+4-1)=4
  • 第二个没有初始化没有看懂,在网上查了资料后知道了数组的储存,然后我的理解如下:a这个数组储存的地址以我们人类的理解方式就是&a[0]=00 00 00 01(大端储存),但是机器是小端储存实际上是&a[0]=01 00 00 00,
    所以a+1=00 00 00 02(大端)=02 00 00 00 (小端),(接下来就晕了)所以ptr2得到了一个小端储存的地址??所以* ptr2=* (a+1)=2,但最后又将2小端输出为02 00 00 00??
  1. 问题:写一个函数,将main函数中的结构体按一定顺序排列。
    分析:此处暂时先借用sort函数,等以后复习了排序直接套用一样的
    解决一:在结构体外定义排序规则,限于使用sort函数
#include<cstdio>
#include<algorithm> //sort的库
#define N 10010
using namespace std;
typedef struct{
	int left,right;
	void out()
	{
		printf("%d %d\n",left,right);
	}
}Range;//这是一个区间的结构体
bool compRule1(const Range &s1,const Range &s2){//按区间先排左端点再排右端点 
	if(s1.left!=s2.left) return s1.left<s2.left;
	return s1.right<s2.right;
}
int main()
{
	freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	Range data[N];
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	scanf("%d%d",&data[i].left,&data[i].right); 
	sort(data,data+n,compRule1);//加入规则
	for(int i=0;i<n;i++) 
	data[i].out();
	fclose(stdin) ;
	fclose(stdout);
	return 0;
}

解决二:重载运算符,这个更通用一点。到时候打了一个归并,快排什么的直接用就是了。

#include<cstdio>
#include<algorithm> 
#define N 10010
using namespace std;
struct Range{
	int left,right;
	void out()
	{
		printf("%d %d\n",left,right);
	}
	
	bool operator < (const Range &s2)const{
		if(left!=s2.left) return left<s2.left;
		return right<s2.right;
	}
}data[N];
int main()
{
	freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	scanf("%d%d",&data[i].left,&data[i].right); 
	sort(data,data+n);
	for(int i=0;i<n;i++) 
	data[i].out();
	fclose(stdin) ;
	fclose(stdout);
	return 0;
}

补充:如果同时有这两种的话,以结构体外定义的规则优先

结语

因为开始写的时间太迟了,这周就只能写这么一点了,感觉有懂了一点指针,但是我认为指针还有1mol的东西等着我去学。(指针杀我)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值