C的回归基础练习篇1
前言
因为一次通宵后整个人这周一直不大聪明的亚子,疯狂的补微积分和工图,完全忘记了还有c,现在开始疯狂补回来。
基础の三道小题
- 题目
编程实现:用户给定一个整数,将该整数逆置之后输出。(如:输入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;
}
- 题目:编程实现:给定一串任意字符串(如: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;
}
- 题目:编程实现:给定一串任意字符串(如: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;
}
提高の一些代码理解
- 代码
#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”)的函数库没有声明啊
- 初始化解释:char* c[]我理解的是定义了一个一维的字符串数组,或者说是指针数组,数组中每个元素都是char*(应该可以看成字符串)的指针;char** cp[]={}是定义了一个指针数组,数组中每个元素都是char** 的指针,其实就是char*** 类型;而这就刚好是cpp的类型。所以从某种意义上讲cpp就是cp,只是cp是一个常量指针,不能自加或自减。
- 输出分析
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同上上。
题外话
这个东西太打脑阔了,我看这个看了一晚上都不是很懂,讲道理真的有人会几个指针夹着[]符号用吗?
- 代码
#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
- 代码
#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??
- 问题:写一个函数,将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的东西等着我去学。(指针杀我)