C++的基本语言学习 , 简单易懂
c++
前言
c++是一种比较早的语言,具体诞生在什么时候我就不记得了
然后进入正文 -- >
正文
part 1 c++程序构造
c++程序构造比较简单实现
#include<bits/stdc++.h> // 头文件 using namespace std; //使用stl空间 ... //一些其他的程序或者定义内容 int main() //主程序 { return 0; }
#include<bits/stdc++.h>
这玩意反正noip在考场上是可以用的,它包含了许多头文件,所以又被称为万能头文件
ps: 本人不推荐使用万能头文件 - 虽然现在没什么大事发生,但是指不定那天ccf傻逼突然给你禁止了那么你就gg了,最好记住每个操作所对应的头文件什么的
using namespace std;
这玩意在oj上面比较多,一般最好每次编程的时候都要加上,而且加了似乎比不加的空间要小(待考证)
int main() { ... }
这玩意是个主程序,一般情况下有人这么写,与上面的写法等价,推荐写上面的
int main(void) { ... return 0; }
括号里面还是可以有参数,
int main(int argc char *argv[]) { ... return 0; }
这个不太常用,因为这个是一个传参的程序 - 基本只有对拍的时候能用到,现在先不讨论
您会发现第一个写法似乎不需要return 0;
乍一看还真是,运行也是正确的,但是为了确保程序正常运行之后结束,我们不考虑不加return 0
的做法,只是告诉你可以不写,但是为了保险还是写上
int main() { ... return 0; }
接下来 -> 主程序设计
part 2 主程序设计
我们现在将要讨论主程序设计的相关事宜
用几个问题来讲 :
q: 如何去定义一个我想要的变量
这个有几个变量是您需要了解的
整形变量 - 整数
变量类型 | 变量上限 | 存储内容 |
---|---|---|
int | \(2^{31}-1\) | 整数 |
short | \(2^{15}-1\) | 整数 |
long | \(2^{31}-1\) | 整数 |
long long | \(2^{63}-1\) | 整数 |
unsigned + xx | 原来类型上限*2 | 整数 |
其中的xx指的是unsigned上面的变量
为什么要讲上限呢?因为如果一个数字存不下了,那么这个变量就会溢出,从最小值从头开始加,就会导致结果的错误
int a=2147483648; printf("%d",a);//结果是负数
浮点数 - 小数
变量类型 | 有效位数 | 存储内容 |
---|---|---|
float | 6-7 | 浮点数 |
double | 15-16 | 浮点数 |
long double | 18-19 | 浮点数 |
浮点数可以理解成小数
浮点数相关注意事项
不能直接比较
float a =1.0; if(a==1) return 0;
这样的写法是错误的
应该是这样的
float a = 1.0; if(a - 1 < 0.0000001) return 0;
还有有的时候浮点数精度问题会出错,如果和答案有些差距建议换成有效位数比较高的long double
其他变量
变量类型 | 存储内容 |
---|---|
char | 单个字符 |
bool | 0或者1 |
string | 字符串 - 多个字符组合在一起 |
void | 空指针 , 无类型 |
char 一般表示的是单个字符
char c='a'; char c=65; char c;
由于c++比较灵活,使得char类型和整形之间可以相互转换
比如
int b=65; char a=b;
ascii表
字符内容 | 对应ascii码的值 |
---|---|
0 - 9 | 48-57 |
a-z | 65-90 |
a-z | 97-122 |
- (减号) | 45 |
上面的最好背下来
char c=48; char c='0';
上面两句是等价的,因为第二句传的是字符 0
而不是0这个数字
考试的时候忘了 赋值输出就好
bool变量-非零即一,空间小,一般用来做标记
string 字符串 - 比较好用,但是个人认为不如字符数组好用,数组是后面的内容
void 一般用来声明函数,因为有一些函数可以不用返回值
这里仔细讲讲全局变量和局部变量
不在函数内定义的 -> 全局变量
所有的函数都可以使用这个变量
在函数内定义的 -> 局部变量
只有定义它的函数才能够使用
局部数组容量 < 全局数组容量
因此,我们一般使用全局数组,局部变量
这里还要介绍一个东西 : sizeof
sizeof(变量名)返回的是变量类型占用存储空间的大小
用处不大,最多参考着定数组大小
接下来 , --> 变量的读入
part 3 变量的读入
#include<cstdio> using namespace std; int main() { int a; long long b; short c; char d; bool e; float f; double g; long double h; scanf("%d",&a); scanf("%lld",&b); scanf("%hd",&c); scanf("%d",&c);// short的两种读入方式都可以 scanf("%c",&d); scanf("%d",&e);//可以用整型方式输入输出没问题 scanf("%f",&f); scanf("%lf,&g); scanf("%llf",&h); printf("%d %lld %hd\n",a,b,c); printf("%d %lld %d",a,b,c); return 0; }
这里的scanf和printf从属于
#include<cstdio>
的,是一种c语言的输入输出方式,c++中也能够用,读入输出的速度很快,比较推荐
scanf("%lld",&b);
这个里面的%lld表示的是格式,&是地址符,您只要知道要这么做就行,不这么做要么re(runtime error : 运行时错误) ,要么ce(编译错误),要么wa(wrong answer,错误答案),有人不加地址符没事,但是这只是个例的语句,还是要加的
因为”“
里面的是输入格式,%d
是变量的输入格式,还可以有
scanf("%d %d",&n,&m);
输入两个int变量n,m,中间用空格隔开,其实中间的格式操作符有很多,读者可以自己去查
printf("%d",b);
格式操作符和scanf一样,输出的时候%d
是变量格式控制符,可以在""
内填其他的要输出的内容
printf("青山");
只是后面变量名不需要加上地址符,后面还可以加上回车控制符\n
,右对齐什么的,保证宽度至少为5位,就是%nd
,然后%0nd
用得比较多,表示输出的整型宽度至少为n位,不足n位用0填充,还有对于浮点数来说,可以%0.nf
来保留n位输出
printf("%5d\n",b); printf("%-5d\n",b); long double b; printf("%0.5llf\n",b);
然后string类型的不能够使用scanf读入
#include<iostream> using namespace std; int main() { int a; long long b; short c; ...//其他的都一样 cin>>a>>b>>c; cout<<a<<" "<<b<<" "<<c<<endl; cout<<a<<" "<<b<<" "<<c; return 0; }
一般cin和cout比较方便,没有格式什么的设定,但是它的速度十分的慢,所以一般情况下为了防止ccf老人机卡您的程序,我并不推荐您用cin和cout,虽然有取消同步从而加速的操作,但是如果恰巧您的printf和scanf之类的出现在程序中,那么迟早要出事
还有一个我推荐scanf和printf不推荐cin和cout的原因是cout保留n位输出和printf可能有不一样的地方,而造数据的一般用printf,所以最好不要用cin和cout
不过cin一个string类型的变量还是很不错的
下一章 -> 数组
part 4 数组
现在我们已经学完了变量的定义方式那么:
q: 现在要求输入n个数字,并原样输出
输入格式
两行,第一行,一个数字n
第二行,n个用空格隔开的数字
输出格式
一行,n个用空格隔开的数字
对于这道题目而言我们可以这么来理解 - 输出一个数组
其实还有一种在线做法,十分简单,但是因为没有讲循环,先当做数组的练习题
不管是什么类型我们都可以定义数组
定义方式
变量类型 + 数组名 + [ 数组大小 ] ;
举个例子
int ans[10086];
int
- 变量类型
ans
- 数组名
[10086]
数组大小
数组的用法:
数组赋初值
int a[3]={1,2,3}; //数组大小为3,初始值为a[0]=1,a[1]=2,a[2]=3; int a[]={1,2,3};//和上面的语句等价,一定要赋初值,然后系统自动分配空间 int a[3]={};//数组初始化为零 int a[3]={0};//和上面的语句等价 int a[3]={1,2};//这也是可以的,只是没有赋值的为0,也就是a[0]=1,a[1]=2,a[2]=0;
这里要注意的是:数组从零开始,也就是说,
int a[n]; printf("%d",a[n]);
是错误的,它只到a[n-1];
还有一种初始值操作:
#include<cstring> memset(a,0,sizeof(a));
但是好像只能为0或者-1,还有16进制的相关问题(不知道进制的可以自己去学)
因为这个地方的参数,也就是memset里面的那个数字(在上面的例子中是0),然后我们可以发现的是,这个参数赋值是赋值到int变量的4个byte中,也就是说,一个数字赋值为0 是这样的
0000 | 0000 | 0000 | 0000 = 0
而 0x代表的就是16进制,所以0x3f3f3f3f代表的就是
因为\(3_{(10)}={11}_{(2)}\),而且\(f_{(16)}=15_{(10)}=1111_{(2)}\),十六进制位没有的数字用0补齐,十六进制在二进制中4位表示一个数字
\[{00111111001111110011111100111111}_{(2)} = {0x3f3f3f3f}_{(16)}\]
所以也就是memset(a,0x3f,sizeof(a));得到数字的来由.
而之所以赋值为1不行的原因是
\[0001 | 0001 | 0001 | 0001 = 1000100010001_{2} = 16843009\]
所以与我们预想的不一样
所以记住,memset只能够赋值0,-1,0x3f(得到结果为0x3f3f3f3f)
其中的0x3f3f3f3f是一个\(10^9\)数量级的数字,但是
2*0x3f3f3f3f < 0x7fffffff (2147483647也就是\(2^{31}-1\))
\[0x7fffffff = 0111 | 1111 | 1111 | 1111 | 1111 | 1111 | 1111 | 1111_{(2)} = 1111111111111111111111111111111_{(2)}=2^{31}-1\]
我们一般把inf(无穷大)定为0x3f3f3f3f的原因是在将来的最短路学习中,如果我们选择了max_int,那么就算是再加上1也会溢出,而这里的无穷大即使加上无穷大也是比max_int要小的,所以为了保险期间一般选择0x3f3f3f3f作为无穷大的值
学好latex(上面数学公式排版的格式规范)还是很重要的
字符数组的操作
序号 | 操作方式 | 意义 |
---|---|---|
1 | strcpy(s1,s2) | 复制字符串 s2 到字符串 s1 |
2 | strcat(s1,s2) | 连接字符串 s2 到字符串 s1 的末尾 |
3 | strlen(s1) | 返回字符串 s1 的长度 |
4 | strcmp(s1,s2) | 返回s1与s2的比较结果 |
5 | strchr(s1,ch) | 返回一个指针,指向字符串s1中字符ch的第一次出现的位置 |
6 | strstr(s1,s2) | 返回一个指针,指向字符串s1中s2的第一次出现的位置 |
初始化字符数组 :
c 风格的字符串起源于 c 语言,并在 c++ 中继续得到支持。字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 “hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “hello” 的字符数多一个。
char greeting[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
其实,您不需要把 null 字符放在字符串常量的末尾。c++ 编译器会在初始化数组时,自动把 ‘\0’ 放在字符串的末尾。所以也可以利用下面的形式进行初始化
char greeting[] = "hello";
以下是 c/c++ 中定义的字符串的内存表示:
字符串的操作
初始化字符串:
string str; //生成一个空字符串 string str ("abc") //等价于 str="abc"<br> string str ("abc", strlen) // 将"abc"存到str里,最多存储前strlen个字节 string s("abc",stridx,strlen) //将"abc"的stridx位置,做为字符串开头,存到str里.且最多存储strlen个字节. string s(strlen, 'a') //存储strlen个'a'到str里
所有字符串的操作:
str1.assign("abc"); //清空string串,然后设置string串为"abc" str1.length(); //获取字符串长度 str1.size(); //获取字符串数量,等价于length() str1.capacity(); //获取容量,容量包含了当前string里不必增加内存就能使用的字符数 str1.resize(10); //表示设置当前string里的串大小,若设置大小大于当前串长度,则用字符\0来填充多余的. str1.resize(10,char c); //设置串大小,若设置大小大于当前串长度,则用字符c来填充多余的 str1.reserve(10); //设置string里的串容量,不会填充数据. str1.swap(str2); //替换str1 和 str2 的字符串 str1.puch_back ('a'); //在str1末尾添加一个'a'字符,参数必须是字符形式 str1.append ("abc"); //在str1末尾添加一个"abc"字符串,参数必须是字符串形式 str1.insert ("abc",2); //在str1的下标为2的位置,插入"abc" str1.erase(2); //删除下标为2的位置,比如: "abcd" --> "ab" str1.erase(2,1); //从下标为2的位置删除1个,比如: "abcd" --> "abd" str1.clear(); //删除所有 str1.replace(2,4, "abcd"); //从下标为2的位置,替换4个字节,为"abcd" str1.empty(); //判断为空, 为空返回true
鸣谢: zerozone零域
大佬和lifeyx
大佬在网上发布的博客,收益匪浅
***
数组的输入方式
char
类型
char c; scanf("%c",&c); cin>>c; c=getchar();
上面三种语句都行,但是一般scanf容易出错,cin又太慢,所以我是比较推荐getchar(),它的作用是读入单个字符
char[]
类型
char c[10]; scanf("%s",c); gets(c);//不能使用
其中的gets是在#include<cstring>
的里面,但是在比赛的时候用的是linux的系统,使用gets会报错,所以不能使用,所以只能用scanf,读入快,结束标志是空格或者换行 ,千万注意scanf读入字符数组的时候没有地址符
string
类型
string a; cin>>a;
这个是我推荐的string读入的写法,但是我不推荐用string类型,最好使用字符数组
输出的话
char
类型
char c; putchar(c);//最快最方便的
char[]
类型
char c[10]; printf("%s",c);//也是可以用的中最快最方便的
string
类型
string s; cout<<s;
我还是只是推荐写法,不推荐用string写程序
除了char和string,都是推荐用printf和scanf输入的
具体要求和单个变量时一致,加上[当前序号]
即可
举例来讲
for(int i=0;i<n;i++) scanf("%d",&a[i]);
你阅读之后可以发现这个for是从哪里蹦出来的,之前没有学啊?
没学没关系,我现在教你,这货叫做循环,一般还有while,do while一共三种循环语句
for语句
for(表达式1;表达式2;表达式3) { 语句1; 语句2; 语句3; } //或者 for(表达式1;表达式2;表达式3) 一个语句;
一般是这样的格式,其中的表达式1一般是定义变量,变量赋初值,表达式2一般是约束条件,只有满足约束条件的时候才能够继续循环,不满足的时候就退出循环,表达式3是改变循环条件变量的值,使它在运行若干时长后停止循环
举个例子
for(int i=0 (循环变量,定义整型变量i 初始值为0);i<n (整型变量i必须小于n));i++(循环变量自增))) scanf("%d",&a[i]);
认真的读者可以发现
i++ 是什么? 其实i++ 就是 i=i+1;把i本身的值+1,但是理论速度更快,更方便,如果看到了a[i++]的,那么说明它是在执行完了这个语句之后再把i自增,如果是a[++i] ,那么就是先把i自增,再执行这个语句,i--和--i都是这样。
所以我们的程序将会遍历(以n=3为例)
a[0],a[1],a[2];
到了i=3的时候我们发现i=n了,那么我们跳出循环来
这个时候我们讲讲判断符
判断符 | 用处 |
---|---|
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
== | 等于 |
&& | 且 |
|| (无法原样保留) |
或 |
!= | 不等于 |
就是这些
前面的一些判断符我不多说,后面的可能读者会有点疑惑
&&表示的是 而且
for(int i=0;i<j&&i>0;i++)
其中的&&表示的就是i
||表示的是 或
for(int i=0;i<j||i>0;i++)
其中的||表示的就是i
!= 表示的是 不等于
也就是\(\ne\),这个应该都学过
将来我们还要学到位运算
保留精力,以后再讲
下一章 -> while , do while
课后作业
没错,以后每次都有课后作业了
可以考虑截屏,也可以发文本,要求必须是可执行程序
给定一个长度为n的数列,第一行先输入n,第二行,输入n个用空格隔开的数字,原样输出n个数字,用空格隔开,要求必须使用数组
给定一个长度为n的数列,第一行先输入n,第二行,输入n个用空格隔开的数字,原样输出n个数字,用空格隔开,要求不能使用数组
给定一个数字n,要求你输出一行数字,分别为n,n-1,n-2,n-3,...,1(倒序输出))中间用空格隔开
给定一个数字n,要求你输出一行数字,分别为1,2,3,4,...,n-1,n(正序输出))中间用空格隔开
给定一个字符串,以换行为结尾,要求你原样输出而且不使用字符数组或者字符串
while语句
格式
while(判断条件) { 语句1; 语句2; }
while(判断条件) 语句1;
就是上面两种
还有
while(t--)
上面的写法比较常见,因为首先是判断t的值,再去减,和下面的语句等价
while(t) t--;
t本身是一个数字,而这个数字也可以用来表示判断的条件,当这个数字是0的时候t不是真,否则t$\geqslant$1的时候t这个数字作为判断条件为真,也就是
数的值 | 判断的结果 |
---|---|
= 0 | 假 |
$\geqslant$1 | 真 |
所以这个时候,只有t一直减直到为0的时候停止循环
为了简便我们一般采用两种语句的前者
举个例子
int i=10; while(i--) { printf("%d ",i); }
得到的结果请自己思考
do while语句
这个语句与while
语句不同的原因是:
先执行do
里面的语句再去判断while
里面的判断条件是否成立,而while和for都是先看的条件是否成立
do { ... } while(判断条件);
或者
do 一个语句 while(判断条件);
就是看着不舒服
记得一定要在while后面加分号
一个活生生的例子
int i=10; do i--,printf("%d ",i); while(i>1);
结果还是读者自己思考
下面讲 -> 判断语句和运算符优先级
part 5 判断语句和优先级
判断语句也不多,就两种
if 语句
if(判断条件) 一个语句;
if(判断条件) { 语句1; 语句2; 语句3; ... }
else
语句一般是指,在不满足与它匹配的if中判断条件的前提下执行else内的语句
if(a==1) printf("1"); else printf("0"); if(a==1) printf("1"); if(a!=1) printf("1");
上面两句话等价
注意,else必须与if对应,每个else都必须有一个if对应,不然就不对,因为这样就没有反面的判断条件了
if() { if() { if() { ... } else { } } else { } } else { }
if和else可以相互嵌套,但是不能只有else没有if
判断条件前面讲过了,不懂得私信我
switch 语句
一个活脱脱的例子
#include<cstdio> using namespace std; int main () { char grade=getchar(); switch(grade) { case 'a' :puts("真棒!");break; case 'b' :puts("好样的!");break; case 'c' :puts("再试一下?");break; case 'd' :puts("过关!");break; case 'e' :puts("不过关!");break; default :puts("成绩无效!"); } printf("您的成绩是:%c\n",grade); return 0; }
switch(变量) { case 1 : case 2 : case 3 : ... default : }
其中的case多少可变,而且这个case后面跟的参数是当变量为此参数时执行这个命令,也就相当于
if(变量 == case参数) 执行语句;
case后面的语句可以是多个的
变量可以不是int类型的,case参数以变量为准,比如下面的也是可以的
switch(grade) { case 'a' :puts("真棒!");break; case 'b' :puts("好样的!");break; case 'c' :puts("再试一下?");break; case 'd' :puts("过关!");break; case 'e' :puts("不过关!");break; default :puts("成绩无效!"); }
这个地方枚举的是等级的字符
default
就是当上面的所有case条件全部不满足,那么就执行当前语句
比如上面那个程序我们如果输入的是f,那么得到的就是成绩无效
需要记住的是 - 字符类型的是'字符'
,而字符串是"字符串"
,一个是单引号,一个是双引号
也就是说:
char c; if(c=='a') return 0;//正确 if(c=="a") return 0;//错误 putchar('a');//正确 putchar("a");//错误
在判断语句中间,字符串不能够直接比较,有一个函数但是不推荐
一般这个双引号是这样的
printf("字符串"); puts("字符串");
一般可以认为puts
输出完字符串之后会自动换行,但是printf
不会。
puts
比printf
块
关于break
和continue
的事情
break
表示退出当前循环/判断,必须单独成为一个语句
continue
表示跳过当前循环/判断,继续下个循环内容,必须单独成为一个语句
很早以前的书中还有goto
这种操作,但是太随意了,被人们扔了,所以不能使用,现在没有什么书上有,也没人用
switch(grade) { case 'a' :puts("真棒!");break; case 'b' :puts("好样的!");break; case 'c' :puts("再试一下?");break; case 'd' :puts("过关!");break; case 'e' :puts("不过关!");break; default :puts("成绩无效!"); }
所以这段话中的case
后面的break
就是跳出当前判断,如果不加上的话,程序将继续查看后面的case
值,直到遇见下一个break
或者最后的default
才会跳出
所以default
的break
语句不是必须的
优先级
优先级比较好理解,就是*/
号比+-
的优先级高,在没有括号的前提下,先执行运算级高的部分 感谢小学数学老师
所以,在c++中的运算符操作一样是有优先级的
具体内容参照c++运算符优先级
part 6 c++ 基本运算
c++中的数学运算
原来数学中代表的内容 | 在c++里面 |
---|---|
× | * |
÷ | / |
+ | + |
- | - |
^ | pow(a,b)也就是(\(a^b\)) |
mod(取余) | % |
需要注意的是,当整数/另一个整数 , 得到的结果将会取整,也就是说
4/3 == 1
%号代表的是一个数除另外一个数的余数,我们知道,一个数除另一个数有两个结果 - 商 和 余数
这个商就是/
,余数就是%
规定/
,%
后面不能为0,不然报错误 - 浮点数例外(linux特产)
还有一个特别屌丝的东西 :
位运算
位运算是什么?首先我们需要了解二进制是什么
二进制也就是我们所说的非零即一,所有的数字都可以表示成0和1组合的数字。
因为某些匹克操作,二进制十分的强大,所以被用来搞事情
先来了解一下进制转换
\(n\)进制转\(10\)进制
这个看着比较骚,实际上还好
也就是每个位上的数字去乘进制数的当前所在位-1次方,举个例子
\[1 + 1 = 10_{(2)}\]
为什么呢?因为
\[10_{(2)} = 0*2^0+1*2^1\]
好了讲了半天(才五行)那么我们继续讲怎么实现
int r,len = n,sum=0;//r进制,len为数字长度(数字有多少位),sum为总和,也就是在10禁止下的数字 for(int i=1;i<=n;i++) sum = sum + a[i] * pow(r,i-1); printf("%d",sum);
至于pow是什么看下面:
c++有一个库,包含各种骚操作
#include<cmath> double acos(double x) 返回x的反余弦弧度。 double asin(double x) 返回x的正弦弧线弧度。 double atan(double x) 返回x的反正切值,以弧度为单位。 double atan2(doubly y, double x) 返回y / x的以弧度为单位的反正切值,根据这两个值,以确定正确的象限上的标志。 double cos(double x) 返回的弧度角x的余弦值。 double cosh(double x) 返回x的双曲余弦。 double sin(double x) 返回一个弧度角x的正弦。 double sinh(double x) 返回x的双曲正弦。 double tanh(double x) 返回x的双曲正切。 double exp(double x) 返回e值的第x次幂。 double frexp(double x, int *exponent) 返回的值是尾数,而指数的整数yiibaied是指数。 结果值是x =尾数* 2 ^指数。 (translate by google ) double ldexp(double x, int exponent) 返回x乘以2,增加到指数幂。(translate by google ) double log(double x) 返回自然对数的x(基准-e对数)。 double log10(double x) 返回x的常用对数(以10为底)。 double modf(double x, double *integer) 返回的值是小数成分(小数点后的部分),并设置整数的整数部分。 double pow(double x, double y) 返回x的y次方。 double sqrt(double x) 返回x的平方根。 double ceil(double x) 返回大于或等于x的最小整数值。 double fabs(double x) 返回x的绝对值 double floor(double x) 返回的最大整数值小于或等于x。 double fmod(double x, double y) 返回的x除以y的余数。
要用的时候加个头文件,按照规范使用就行,只要背一些常用的就行。
需要注意的是 : c++中间在运算的时候不像现代数学有大括号中括号花括号,不管是什么都是小括号
printf("%d",((a+b)*c+d)/e)
对,中间用的就是小括号,不管怎样都是小括号
\(10\)进制转\(n\)进制
我相信这个都不会会的略过
简单来讲,就是10 -> n进制的方式
其实就是原数不断除进制数,记录余数,然后反着组成
举个例子 :
\[10_{(10)} = 1010_(2)\]
10 % 2 = 0,10 / 2 = 5; 5 % 2 = 1,5 / 2 = 2; 2 % 2 = 0,2 / 2 = 1; 1 % 2 = 1,1 / 2 = 0; 算法结束
倒序输出,也就是1010
,答案是对的没错
用程序表达也就是
int sum=n,r,len=0,ans[105];//sum表示十进制数,r表示要转换的进制数,len表示r进制数的长度,ans存答案 while(sum) { ans[++len]=sum % r; sum = sum / r; } for(int i=len;i>=1;i--) printf("%d",ans[i]);
有关位运算的操作
这种骚事c++也能干出来
操作也不多,就那几个,但是理解需要时间
& ^ | << >>
就这五个,嗯
我一个一个讲吧
&
按位与,至于按位怎么来的我想应该是因为它一位一位看吧哈哈哈
举个例子
1010101
&101010
也就是
在一个位上,如果都是1,那么就是1,否则为0,如果有一个位另外一个数字没有,那么那个数字的哪一位是0,自动补零,一般写出来省略0
所以答案就是
0000000
也就是0
舒不舒服哈哈哈
^
按位异或
可以理解成两个数字某一位上的数字相同的时候是0,不同的时候是1,那么为什么不反过来呢?数字前面的前置零怎么办!
举例更好理解
1010101
^101010
1111111
矮油我去,怎么又全是1了?
明明就是这样balabala
|
按位或
可以理解为两个数字某一位上的数字中至少1个是1的时候答案是1,否则就是0
也就是说
1010101
|101010
1111111
矮油怎么还是1111111?受不了换样例!
屁事多!
11111111
|1111111
11111111
凑合着看吧
<<
左移,可以理解成*2,因为它就是把一个数字在最后加上一个0
>>
右移,可以理解成/2,因为它就是把一个数字的最后一位去掉
这就是位运算
***
运算符
在c的语言中,有这样的操作,支持快速的赋值
a += b; a -= b; a *= b; a /= b; a %= b; a &= b; a ^= b; a |= b; a <<= b; a >>= b;
这个操作是从右向左的,也就是说,下面这个式子等价于:
a += a *= a /= a-6; //等价于 a /= a-6; a *= a; a += a;
那么这些操作符是什么呢?这些操作符表达的意义也就是
a += b; a = a + b; a -= b; a = a - b; a *= b; a = a * b; a /= b; a = a / b; a %= b; a = a % b; a &= b; a = a & b; a ^= b; a = a ^ b; a |= b; a = a | b; a <<= b; a = a << b; a >>= b; a = a >> b;
常量
也就是一个一直保持不变的量,这个时候有两种定义方式
define
#define
可以理解成文本替换,用法简单
#define 替换文本 目标文本
注意,最后没有分号,所以我们不能在define后面写注释,因为这样很有可能一起替换了
举个例子
#define ll long long #define maxn 10005 #define max(a,b) ((a>b) ? a : b)
然后这个时候就可以
#include<cstdio> using namespace std; #define ll long long #define maxn 10005 #define max(a,b) ((a>b) ? a : b) int main() { ll a=1,b=2,c=maxn; printf("%lld %lld",max(a,b),c); return 0; }
运行结果是
2 10005
其中的
(a>b) ? a : b
是一个三目运算符,它可以简单理解为
(判断条件) ? 语句1 (成立才执行) : 语句2 (否则,不成立才执行)
等价于
if(判断条件) 语句1; else 语句2;
然后#define就这样用,一般还有
#define int long long
也是可以的,但是主函数怎么办?没关系,
signed = signed int = int
所以我们可以考虑这样写
signed main()
其实#define
主要是替换内容,但是const
是真正的赋初值
const
#include<cstdio> using namespace std; #define ll long long const int maxn = 10005; #define max(a,b) ((a>b) ? a : b) int main() { ll a=1,b=2,c=maxn; printf("%lld %lld",max(a,b),c); return 0; }
答案和用#define的一样,格式是
const 变量类型 变量名 = 初始值 ;
注意,const
后面有分号
在编译的时候,如果用#define
而define的变量出错,它会提示你你替换的那个目标文本有问题,而不是你原来的文本有问题,但是const就会明确告诉你变量名,是哪个变量出错一清二楚
还有,#define
后面不能接0x3f3f3f3f
和0x7fffffff
,但是const可以
基础内容讲解完毕! 有什么不懂的可以私信我,大胆地提问没关系
课后作业
写出一个判断闰年的程序,要求输入一个数字代表年份,一行输出,如果是闰年则输出
yes
,如果不是那么输出no
,判断规则是:能被4整除的 大多 是闰年,能被100整除而不能被400整除的年份不是闰年,能被400整除的是闰年,能被3200整除的也不是闰年-
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 10 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 30 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
现在已知 10 个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。
输入包括两行数据。第一行包含 10 个 100 到 200 之间(包括 100 和 200 )的整数(以厘米为单位)分别表示 10 个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。第二行只包括一个 100 到 120 之间(包含 100 和 120 )的整数(以厘米为单位),表示陶陶把手伸直的时候能够达到的最大高度。
输出一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。[noip普及组2005年]
-
某校大门外长度为l的马路上有一排树,每两棵相邻的树之间的间隔都是 1 米。我们可以把马路看成一个数轴,马路的一端在数轴 0 的位置,另一端在 l 的位置;数轴上的每个整数点,即 0,1,2,…,l,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入输出格式
输入格式:
第一行有 2个整数 l(1\(\le\)l$\le$10000)和 m(1 \(\le\)m$\le$100), l 代表马路的长度, m 代表区域的数目, l 和 m 之间用一个空格隔开。
接下来的 m 行每行包含 2 个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。输出格式:
1 个整数,表示马路上剩余的树的数目。[noip普及组2005年]
-
津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。
输入输出格式
输入格式:
输入包括 7 行数据,分别表示周一到周日的日程安排。每行包括两个小于 10 的非负整数,用空格隔开,分别表示津津在学校上课的时间和妈妈安排她上课的时间。输出格式:
一个数字。如果不会不高兴则输出 0,如果会则输出最不高兴的是周几(用 1, 2, 3, 4, 5, 6, 7分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度相当,则输出时间最靠前的一天。[noip普及组2004年]
-
某校的惯例是在每学期的期末考试之后发放奖学金。发放的奖学金共有五种,获取的条件各自不同:
院士奖学金,每人8000元,期末平均成绩高于80分(>80),并且在本学期内发表11篇或11篇以上论文的学生均可获得;
五四奖学金,每人4000元,期末平均成绩高于85分(>85),并且班级评议成绩高于80分(>80)的学生均可获得;
成绩优秀奖,每人2000元,期末平均成绩高于90分(>90)的学生均可获得;
西部奖学金,每人1000元,期末平均成绩高于85分(>85)的西部省份学生均可获得;
班级贡献奖,每人 850 元,班级评议成绩高于80分(>80)的学生*均可获得;
只要符合条件就可以得奖,每项奖学金的获奖人数没有限制,每名学生也可以同时获得多项奖学金。例如姚林的期末平均成绩是87分,班级评议成绩82分,同时他还是一位学生*,那么他可以同时获得五四奖学金和班级贡献奖,奖金总数是4850元。现在给出若干学生的相关数据,请计算哪些同学获得的奖金总数最高(假设总有同学能满足获得奖学金的条件)。
输入输出格式
输入格式:
第一行是 1 个整数 n(1\(\le\)n$\le$100),表示学生的总数。接下来的 n 行每行是一位学生的数据,从左向右依次是姓名,期末平均成绩,班级评议成绩,是否是学生*,是否是西部省份学生,以及发表的论文数。姓名是由大小写英文字母组成的长度不超过 20的字符串(不含空格);期末平均成绩和班级评议成绩都是0到100之间的整数(包括 0 和 100 );是否是学生*和是否是西部省份学生分别用1个字符表示,y表示是,n表示不是;发表的论文数是0到10的整数(包括 0 和 10 )。每两个相邻数据项之间用一个空格分隔。
输出格式:
包括 3 行。第 1 行是获得最多奖金的学生的姓名。
第 2 行是这名学生获得的奖金总数。如果有两位或两位以上的学生获得的奖金最多,输出他们之中在输入文件中出现最早的学生的姓名。
第 3 行是这 n 个学生获得的奖学金的总数。
提示: 名字用字符数组,
scanf %s
输入,printf %s
输出[noip提高组2005年]
推荐阅读
-
【基于C++和Python的Opencv3学习笔记之基本图形的绘制】
-
为什么在美国的cs编程入门课大多有java和python。而在国内首先学习的语言是c/c++?
-
C++的基本语言学习 , 简单易懂
-
C语言/C++编程学习:不做C/C++工作也要学C/C++的原因!
-
c++语言的学习笔记代码与笔记注释《函数部分》
-
编程语言的学习 ------ python3文件读取+登录简单验证(优化1)
-
编程语言的学习 ------ python3文件读取+用户登录简单验证(优化2)
-
编程语言的学习 ------ python3的文件读取写入(简单登录验证)
-
Visual studio 2019 支持graphics.h 库的支持,简单易懂,妈妈再也不用担心你的学习
-
C++编程语言的四项基本准则