所有代码都展示main函数里面的代码
辗转相除法
int u = 32;
int v = 32;
//如果v=0,计算结束,u就是最大公约数
//v!=0计算u/v的余数,让u=v v=余数
while(v!+0)
{
int temp = u%v;
u = v;
v = temp;
}
printf("%d",u);
从计算机到程序再到算法
计算机的思维和优势是把所有可能列出来挨个试(枚举)
用二分法可以进一步简化运算提高算法效率
程序的执行
解释:借助一个程序,那个程序能试图理解你的程序,然后按照你的要求执行
编译:借助一个程序,那个程序能将你的程序翻译成机器语言后执行
编译和解释的区别与看法
需求:
int price = 0;
printf("请输入金额(元)");
scanf("%d",&price);
int change = 100 - price;
printf("找您%d元。\n",change);
优化
int price = 0;
const int AMOUNT = 100;
printf("请输入金额(元)");
scanf("%d",&price);
int change = AMOUNT - price;
printf("找您%d元。\n",change);
const是个修饰符,加在int前面,const修饰变量一经初始化则无法修改,还可以进行再次优化,让用户输入那个变量的值,而不是固定的100
变量定义的一般形式:<类型名称><变量名称>;
在数学中a=b和b=a意义完全相同,但是在程序设计中意义完全相反
所有变量在第一次使用时之前应被赋值(初始化)
<类型名称><变量名称>=<初始值>;
scanf("%d",&price);
要求scanf这个函数去读入下一个整数,读到的结果赋值给price
双引号里的时格式字符串,%d表示读取整数
小心price前面的&,在scanf变量前要加&
int hour1,minute1;
int hour2,minute2;
scanf("%d %d",&hour1,&minute1);
scanf("%d %d",&hour2,&minute2);
int t1 = hour1*60 + minute1;
int t2 = hour2*60 + minute2;
int t = t1 + t2;
printf("时间差是%d小时%d分",t/60,t%60);
//利用t/60抽象出小时,t%60抽象出分钟
int a,b;
scanf("%d %d",&a,&b);
//人们利用浮点数表达所有的带小数点的数,当浮点数和整数放到一起运算的时候,c会将整数转换为浮点数,然后进行浮点运算
double c = (a+b)/2.0;
printf("%d和%d的平均值为%lf",a,b,c);
数据类型 | 中文名称 | 格式字符串 |
---|---|---|
double | 双精度浮点数 | “%lf” |
float | 单精度浮点数 | “%f” |
int | 整数 | “%d” |
int a = 5;
int b = 6;
int t = 0;
t = a;
a = b;
b = t;
printf("a=%d b=%d",a,b);
+= -= *= /= %= ++ –
这些符号是因为c语言继承了曾经的机器语言
count ++;
count += 1;
count = count + 1;
上述三种是一个意思都能完成加一
a++表示加一以前的值
++a表示加一以后的值
但这俩种运算过后,下一行再用a都是加一过后的值
/*if(条件成立){
...;
}*/
// ==相等 !=不等 >大于 >=大于或者等于 <小于 <=小于或等于
//当两个值的关系符合关系运算符的预期时,关系运算的结果为1,否则为0
printf("%d\n",5==3);
printf("%d\n",5>3);
printf("%d\n",5<3);
//所有的关系运算符的优先级比算术运算的低,但是比赋值运算的高
7 >= 3+4;
int r = a>0;
//判断是否相等的优先级比其他的低
//连续的关系运算是从左到右进行的
//初始化
int price = 0;
int bill = 0;
//读入数据
printf("请输入金额");
scanf("%d",&price);
printf("请输入票面");
scanf("%d",&bill);
printf("应该找您:%d\n",bill-price);
但是我们上面那个程序无法判断给够钱了嘛,即判断票面够不够
我们进行一个逻辑判断对程序进行优化
//初始化
int price = 0;
int bill = 0;
//读入数据
printf("请输入金额");
scanf("%d",&price);
printf("请输入票面");
scanf("%d",&bill);
if(bill>=price)
{
printf("应该找您:%d\n",bill-price);
}
else
{
printf("钱不够还差:%d\n",price-bill);
}
int a,b;
printf("请输入两个正整数:");
scanf("%d %d",&a,&b);
int max = 0;
if(a>b)
{
max = a;
}
else
{
max = b;
}
printf("%d和%d的最大值是%d",a,b,max);
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
int max = 0;
if(a>b)
{
if(a>c)
{
max = a;
}
else
{
max = c;
}
}
else
{
if(b>c)
{
max = b;
}
else
{
max = c;
}
}
printf("最大值是%d",max);
案例二也可以用别的方法解决,如冒泡排序等
有如下分段函数,要求设计一个程序,输入x输出y
f(x) = -1 x<0
f(x) = 0 x=0
f(x) = 2x x>0
//只展示if部分
if(x<0)
{
f = -1;
}
else if(x=0)
{
f = 0;
}
else
{
f = 2*x;
}
编程习惯tips
if语句常见错误
若级联过多,执行效率会非常低,可用switch结构
switch(控制表达式){
case 常量:
语句;
break;
case 常量:
语句;
break;
default:
语句
break;
}
控制表达式只能是整数类型的结果
常量表达式可以是常数,也可以是表达式
switch语句可以看作一种基于计算的跳转,多个值对应一个语句
案例:成绩转换
成绩大于等于90为A
成绩大于等于80为B
成绩大于等于70为C
成绩大于等于60为D
成绩小于60为E
int grade;
scanf("%d",&grade);
grade /= 10;
//我们只抽象出十位数进行运算,这样就可以使用switch结构
switch(grade)
{
case 10:
case 9:
printf("A\N");
break;
case 8:
printf("B\N");
break;
case 7:
printf("C\N");
break;
case 6:
printf("D\N");
break;
default:
printf("E\N");
break;
}
级联>的时候从高往下判断
级联<的时候从下往高判断
int x;
int n = 0;
scanf("%d",&x);
//这行代码是保证输入0的时候输出位数是1
n++;
x /= 10;
while(x>0)
{
n++;
x /= 10;
}
printf("%d\n",n);
tips
优化
我们现实中很多情况都需要先执行一次再判断循环
do-while会先执行一次再判断循环
int x;
int n = 0;
scanf("%d",&x);
do
{
n++;
x /= 10;
}
//这个while后面一定要打分号
while(x>0);
printf("%d\n",n);
拓展案例:计数循环
int count = 100;
while(count>=0)
{
//这两行决定第一个输出和最后一个输出的数据是什么
count--;
printf("%d\n",count);
}
printf("发射\n");
计算机想一个数,然后让用户去猜
猜的时候提醒大了还是小了直到猜中为止
补充知识
程序设计思路
srand(time(0));
int number = rand()%100+1;
int count = 0;
int a = 0;
printf("我已经想好了1-100的整数");
do{
printf("请输入这个1-100的整数");
scanf("%d",&a);
count++;
if(a>number)
{
printf("大了");
}
else
{
printf("小了");
}
}
while(a!=number);
prinf("用了%d次猜中了数字%d",count,number);
让用户输入一系列正整数,最后输入-1结束,然后程序计算出这些数字的平均数和数字个数
程序设计思路
int number;
int sum = 0;
int count = 0;
scanf("%d",&number);
while(number!=-1)
{
sum +=number;
count++;
scanf("%d",&number);
}
printf("%f\n",1.0*sum/count);
输入一个正整数(int范围内的整数),输出逆序的数
程序设计思路
int x = 0;
int sum = 0;
int t = 0;
scanf("%d",&x);
int count = 0;
//防止x改变利用一个变量代替x进行操作
t = x;
//我们先得到x是几位数,为了防止输入的是0,我们要先进行一次运算
t /= 10;
count++;
while(t!=0)
{
t /= 10;
count++;
}
//逆序处理
//有几位数就进行几次运算
for(int i=0;i<count;i++)
{
//抽象出最后一位,并且把x从左往右少一位
int a = x % 10;
x /= 10;
//利用j=count-i-1抽象出每次的一位要变到前面去需要×10的几次方,这种方法也能解决末尾是0的问题因为0*任何数都是0
for(int j=count-i-1;j>0;j--)
{
a *= 10;
}
//计算和即可
sum += a;
}
printf("%d",sum);
案例1:算阶乘
int n;
scanf("%d",&n);
int fact = 1;
int i = 1;
for(i=1;i<=n;i++)
{
fact *= i;
}
printf("%d",fact);
案例2:是否是素数
int x;
scanf("%d",x);
int i;
int isPrime = 1;
for(i=2;i<x;i++)
{
if(x%i == 0)
{
isPrime = 0;
break;
}
else
{
continue;
}
}
if(isPrime = 0)
{
printf("%d不是素数",x);
}
else
{
printf("%d是素数",x);
}
关于for循环
tips
如何用1.2.5角凑10元以下的金额
方案1:接力break
int x;
int one,two,five;
int exit = 0;
scanf("%d",&x);
for(one=1;one<x+10;one++)
{
for(two=1;two<x*10/2;two++)
{
for(five=1;five<x*10/5;five++)
{
if(one+two*2+five*5==x*10)
{
printf("%d1角%d2角%d5角",one,two,five);
//设置一个变量作为出口条件,创建接力break
exit = 1;
break;
}
if(exit == 1)
{
break;
}
}
if(exit == 1)
{
break;
}
}
}
方案2:goto
int x;
int one,two,five;
int exit = 0;
scanf("%d",&x);
for(one=1;one<x+10;one++)
{
for(two=1;two<x*10/2;two++)
{
for(five=1;five<x*10/5;five++)
{
if(one+two*2+five*5==x*10)
{
printf("%d1角%d2角%d5角",one,two,five);
goto FLAG;
}
}
}
}
FLAG:
return 0;
输入一个非负整数,正序输出每一位,每一位中间有空格,最后无空格
程序设计思路
int x;
scanf("%d",&x);
int mask = 1;
while(t>9)
{
t /= 10;
mask *= 10;
}
do
{
int d = x / mask;
printf("%d",d);
if(mask>9)
{
printf(" ");
}
x %= mask;
mask /= 10;
}
while(mask>0);
printf("\n");
方法一:设t为2,如果u,v都能被整除则记下t,t++后重复第二步直到等于u和v的最小值,那么曾经记下的最大的t就是goc
int a,b;
int min=0;
scanf("%d %d",&a,&b);
if(a>b)
{
max = a;
}
else
{
max = b;
}
int ret = 0;
for(int i=0;i<=min;i++)
{
if(a%i==0)
{
if(b%i==0)
{
ret == i;
}
}
}
printf("%d",ret);
方法二:辗转相除法
int u = 32;
int v = 32;
//如果v=0,计算结束,u就是最大公约数
//v!=0计算u/v的余数,让u=v v=余数
while(v!+0)
{
int temp = u%v;
u = v;
v = temp;
}
printf("%d",u);
C是有类型的语言,在使用前必须定义并且确定类型
C以后的语言向俩个方向发展
C语言的类型
sizeof
sizeof是一个运算符,算出表达式在内存中占几个字节
注意
计算机内部一切都是二进制
那我们如何表达负数呢?
在十进制的时候,我们负号其实是独立于数字单独运算
那么二进制负数有三种方案
但是前两种对于人类来说好理解,但是在计算机设计上比较复杂
利用位数上限进行设计
0->00000000
1->00000001
-1->11111111
全一被当作纯二进制看待时,是255,被当作补码看待时是-1
补码的意义就是拿补码和原码可以加出来一个溢出来的0
char c = 255;
int i = 255;
printf("c=%d,i=%d",c,i);
输出结果c的值为-1,i则为255
所以不同类型有不同的范围
负的数字范围会比整数多一个
unsigned
如果我们不想用补码的形式表示,我们可以使用unsigned关键字,让变量表达为纯二进制
正数范围扩大,负数不再表达
unsigned的初衷并非扩展数能表达的范围,而是为了去做纯二进制运算,为了进行移位
案例:计算int类型的最大数
利用原理:超过上限会溢出变成负的最大值,减一以后刚好回归正数最大值
int a = 0;
int b = 0;
while(++a>0);
printf("int数据类型最大数是:%d\n",a-1);
b++;
while((a=a/10)!=0)
{
b++;
}
printf("int数据类型组最大数的位数是:%d",b);
整数的输入输出只有两种形式:int或者long long
一个数字以0开头就是8进制
一个数字以0x开头就是16进制
%0用于8进制
%x用于16进制
计算机内部永远只有二进制,你写的八进制编译的时候会进行转换
8进制和16进制只是如何把数字表达成字符串,与内部如何表达数字无关
16进制一位刚好是4位2进制的数
整数为什么要有那么多种,是为了准确表达内存,做底层程序的需要
但是一般来说,没有特殊需要就选择int
unsigned与否只是输出不同,内部计算是一样的
double与float
float有效数字为7位
double有效数字为15位
总有一块靠近0但不等于0的数字我们无法表达,即靠近0的无穷小无法表达
科学计数法用E表示
输出精度
在%和f之间加上.n可以指定输出小数点后几位,这样的输出是可以做四舍五入的
printf("%.3f\n",-0.0049);
printf("%.30f\n",-0.0049);
printf("%.3f\n",-0.00049);