课程中C语言编程
第一个代码 hello world
01 代码
#include <stdio.h>
int main()
{
/* 我的第一个 C 程序 */
printf("Hello, World! \n");
return 0;
}
02 知识点
#include <stdio.h> 程序的第一行 是预处理器指令,告诉 C 编译器在实际编译之前要包含 stdio.h 文件。
下一行 int main() 是主函数,程序从这里开始执行。
下一行 return 0; 终止 main() 函数,并返回值 0。
令牌(Token)是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。token其实说的更通俗点可以叫暗号。
HTTP 是一种没有状态的协议,也就是它并不知道是谁是访问应用。这里我们把用户看成是客户端,客户端使用用户名还有密码通过了身份验证,不过下回这个客户端再发送请求时候,还得再验证一下。
使用token机制的身份验证方法,在服务器端不需要存储用户的登录记录。
大概流程
客户端使用用户名和密码请求登录。
服务端收到请求,验证用户名和密码。
验证成功后,服务端会生成一个token,然后把这个token发送给客户端。
客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里。
客户端每次向服务端发送请求的时候都需要带上服务端发给的token。
服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据。
标识符 是用来标识变量、函数,或任何其他用户自定义项目的名称。(意思是它用来识别这个和那个的不同的名字)
定义变量时,我们使用了诸如 a、abc、mn123 这样的名字,它们都是程序员自己起的,一般能够表达出变量的作用,这叫做标识符(Identifier)。
标识符就是程序员自己起的名字,除了变量名,后面还会讲到函数名、宏名、结构体名等,它们都是标识符。不过,名字也不能随便起,要遵守规范;C语言规定,标识符只能由字母(A~Z, a~z)、数字(0~9)和下划线(_)组成,并且第一个字符必须是字母或下划线,不能是数字。
第二个代码 找零钱
01 代码
#include <stdio.h>
int main()
{
int price=0
printf("请输入金额(元)");
scanf("%d",&price) ;
int change=100-price;
printf("找您%d元\n",change);
return 0;
}
02 知识点
int price=0; 表示将“=”右边的值赋给左边 变量的名字是price 类型是int
数学中 a=b 即a和b的值相等 而 计算机中 b赋予a int 表示数据类型 整数
int change=100-price 定义了第二个变量
scanf 里面的东西就是输入的东西 Scan Format 格式输入
const 是一个修饰符 加在int的前面 用来给这个变量加上一个const(不变的)属性
第三个代码 身高换算 英寸换成米
01 代码
#include <stdio.h>
int main()
{
printf("请分别输入身高的英尺和英寸,"
"如输入\"5 7\"表示5英尺7英寸:");
int foot;
int inch;
scanf("%d %d",&foot,&inch) ;
printf("身高是%f米。\n",
((foot+inch/12)*0.3048));
return 0;
}
02 知识点
因为两个整数的运算的结果只能是整数
引出浮点数 带小数点 定点数是指小数点是固定的,比如永远在第四位 不过在C语言中是没有定点数的
double 的意思是“双” 本来是“双精度浮点数”的第一个单词 也用来表示浮点数类型
除了double 还有 float (意思就是浮点)表示单精度浮点数
%d 是十进制 整型输出 %lf是双精度浮点型 单精度浮点精确到小数点后六位 双精度浮点精确到15~16位 decimal,十进制 floating point,浮点
%f float %lf long float
单目不变 就是只有一个算子 比如·说a 取一个相反数 -a
赋值 a=b=6 先做b=6 再做a=b=6
第四个代码 a=b b=a
01 代码
#include <stdio.h>
int main()
{
int a=5;
int b=6;
int t;
t=a;
a=b;
b=t;
printf("a=%d,b=%d\n",a,b);
return 0;
}
问题1 把 return 0合在一起 从而编译错误
调试问题
第五个代码 递增递减
01 代码
#include <stdio.h>
int main()
{
int a;
a=10;
printf("a++=%d\n",a++);
printf("a=%d\n",a);
printf("++a=%d\n",++a);
printf("a=%d\n",a);
return 0;
}
02 知识点
递增递减运算符
++ -- 必须是单目运算符 这个算子还必须是变量 它们的作用就是给这个变量+1或者-1
a++=10 作为一个表达式 式子还没完成 缺一个等号
a=11 有了等号 就变成11了
++a=12 这是和a++的区别
a=12
第六个代码
#include <stdio.h>
int main()
{
printf("Programming in C is fun!\n");
return 0;
“f”代表 “formatted”,因为那些函数在输入 / 输出的过程中进行格式化,所以结果都是已经被格式化了的(formatted)数据。
scanf表示从键盘输入指定格式的数据。如:scanf ("%d",x);指从键盘给x输入一个int型(整型)数据。
\n是一个整体,含义只有一个,(输出)回车换行。比如,printf("hello")和printf("hello\n")的区别,前者输出hello后就没了,后者输出hello后当前行就结束了新的数据强制在下一行才能继续,即输出了一个换行符
反斜杠\,这在C++语言里叫转义符号
第七个代码
01 代码
题目
如果已知英制长度的英尺foot和英寸inch的值,那么对应的米是(foot+inch/12)*0.3048。现在,如果用户输入的是厘米数,那么对应英长度的英尺和英寸是多少呢?别忘了1英尺等于12英寸
输入格式:
输入在一行中给出1个正整数,单位是厘米。
输出格式:
在一行中输出这个厘米数对应英制长度的英尺和英寸的整数值,中间用空格分开
输入样: 170
输出样例: 5 6
自写代码
第一次写(把米和英尺寸换过来,采用三个%d %d %d)
#include<stdio.h>
int main()
{
printf("请分别输入身高的英尺和英寸,""如输入\"57\"表示5英尺7英寸:");
int foot;
int inch;
scanf("身高是%f米。\n",((foot+inch/12)*0.3048));
printf("%d %d",&foot,&inch);
return 0;
}
网上代码
#include<stdio.h>
int main()
{
printf("请输入身高,"
"如输入170表示170厘米:") ;
int foot,inch;
int centimeter;
scanf("%d",¢imeter);
foot=centimeter/30.48;
inch=((centimeter/30.48)-foot)*12;
printf("%d %d\n",foot,inch);
return 0;
}
模仿错误
将foot、printf打错
scanf 中 没有加& print f加&
&in是in的地址。
scanf需要把读入的值存入变量中,所以要写&,传地址调用函数。
printf只需要输出值,与变量的地址无关,所以不用加&。如果加了&,就是将地址当作整数输出出来,自然就乱码了。
第八个代码
01 代码
题目
有时候人们用四位数字表示一个时间,比如1106表示11点零6分。现在,你的程序要根据起始时间和流逝的时间计算出终止时间。谈入两个数字,第一个数字以这样的四位数字表示当前时间,第二个数字表示分钟数,计算当前时间经过那么多分钟后是几点,结果也表示为四位数字。当小时为个位数时,没有前导的零,即5点30分表示为530。注意,第二个数字表示的分钟数可能超过60,也可能是负数
输入格式:
输入在一行中给出2个整数,分别是四位数字表示的起始时间、以及流逝的分钟数,其间以空格分隔。注意:在起始时间中,当小时为个位数时,没有前导的零,即5点30分表示为530;流逝的分钟数可能超过60,也可能是负数
输出格式:
输出四位数字表示的终止时间。题目保证起始时间和终止时间在同一天内。
输入样例:
1120 110
输出样例:
1310
函数思维方向
1120 代表11个小时外加20分钟 11*60+20=680 680(起始时间)+110(流逝时间)=790(最终时间) 790/60=13小时 790/60=13 余10 就是1310 怎么在电脑上打出这个数字呢 13*100+10
#include<stdio.h>
int main()
{
int a,d;
int time,pass;
scanf("%d %d",&time,&pass);
a=100+110;
d=(((a/60)*100)+(a%60));
printf("d是%d");
return 0;
}
程序可以运行,但是结果不对。
#include<stdio.h>
int main()
{
printf("请输入起始时间和经过时间");
int a,d;
int time,pass;
scanf("%d %d",&time,&pass);
a=(time/100)*60+(time%100)+pass;
d=(((a/60)*100)+(a%60));
printf("d=%d",d);
return 0;
}
修正:改了公式a即可
出现错误
ld returned 1 exit status(暂未解决)
第九个代码 整数四则运算
本题要求编写程序,计算2个正整数的和、差、积、商并输出。题目保证输入和输出全部在整型范围内。
代码编写
#include<stdio.h>
int main()
{
printf("请输入这两个数");
int a=0;
int b=0;
int d=0;
scanf("%d %d",&a,&b);
d=(a+b+5);
printf("%d",d);
return 0;
}
错误点
一开始没有在printf("%d",d);输入d,输入3 2结果老是3
第十个代码 BCD解密
BCD数是用一个字节来表达两位十进制的数,每四个比特表示一位,所以如果一个BCD数的十六进制是0x12,它表达的就是十进制的12.
但是小明没学过BCD,把所有的BCD数都当作二进制数转换成十进制输出了。于是BCD的0x12被输出成了十进制的18了!
现在,你的程序要输入这个错误的十进制数,然后输出正确的十进制数。提示:你可以把18转换回0x12,然后再转换回12.
输入格式:
输入在一行中给出一个[0,153]范围内的正整数,保证能转换回有效的BCD数,也就是说这个整数转换成十六进制时不会出现A-F的数字。
输出格式:
输出对应的十进制数
输入样例:
18
输出样例:
12
知识点
18 00010010 0x12 (16进制的 0x是为了与其他进制的相区别) BCD=12
BCD数 2的4次方等于16 可以表达十进制中的0-9
例如: 4+9:0100 + 1001 = 1101,而1101为13属于无效码,结果+6(0110),即1101 + 0110 =
1 0011(13)
代码
直接将十进制转化为十六进制即可 18/16=1 18%16=2
第十一个代码 关系代码
#include <stdio.h>
int main()
{
printf("%d\n",5==3);
printf("%d\n",5>3);
printf("%d\n",5<=3);
return 0;
}
运行结果 01 0
第十二个代码
代码
#include <stdio.h>
int main()
{
const int READY=24;
int code=0;
int count=0;
scanf("%d %d",&code,&count);
if(code==READY)
{
if (count<20)
printf("一切正常\n");}
else
printf("继续等待\n");
return 0;
}
知识点
嵌套的if语句
if后面紧跟一个if语句或者if-else语句,就叫嵌套语句
if 或者else语句后面一定要加一个{}
第十三个代码 级联的if-else if
解决问题
f(x)=-1, x<0 =0,x=0 2x,x>0
#include <stdio.h>
int main()
{
int x;
int f;
scanf("%d",&x);
if (x<0){f=-1;}
else if (x==0) {f=0;}
else {f=100*x;}
printf("%d\n",f);
return 0;
}
出现的bug
x=0 不等价于x==0
第十四个代码 while循环
#include <stdio.h>
int main()
{
int x;
int n=0;
scanf("%d",&x);
n++;
x/=10;
while (x>0)
{n++;
x/=10;}
printf("%d\n",n);
return 0;
}
n++;
x/=10; 是为了解决0这个数的问题
while与if 的区别 if一次性 while 循环
循环体需要有改变条件的机会
第十四个代码 do-while循环
这个的话,不管怎样先进入循环
第十五个代码 猜数游戏
1 计算机随机想一个数,记在变量number里
2 一个负责计次数的变量count初始化为0;
3 让用户输入一个数字a
4 count递增(加一) 循环的条件是a和number不相等
5 判断a和number是不相等的,程序则转回到第三步
6 否则,程序输出“猜中”和次数,然后结束
rand 每次召唤这个 就能产生一个随机数
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
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 if (a<number)
{printf("你猜的数小了。");}
}
while (a!=number);
printf("太好了,你用了%d次就猜到了答案。\n",count);
return 0;
}
代码构成
使用了rand函数
并且使用了do while 循环 循环里面有两部分 一部分是你猜的数对不对 另一部分是你猜了多少次
第十六个代码 整数代序
digit=x%10;
x/=10;
第一步是先把最后一个数留下来 最后再把最后一个数给去掉 比如说12345 去掉5 剩下 1234
#include <stdio.h>
int main()
{
int x;
//scanf("%d",&x);
x=12345;
int digit;
int ret=0;
while(x>0){
digit=x%10;
// printf("%d\n",digit);
ret=ret*10+digit;
printf("x=%d,digit=%d,ret=%d\n",x,digit,ret);
x/=10;
}
printf("%d\n",ret);
return 0;
}
第一轮中
ret 初始值为0,因此ret=0+5=5
第二轮中
ret=5*10+4(digit=4)=54
第十七个代码 计算阶乘
阶乘
n!=1*2*3*4*n
写一个程序,让用户输入n,然后计算输入n!
变量:
用户的输入需要一个int的n,然后计算的结果需要用一个变量保存,可以是int的factor,在计算中需要有一个变量不断地从i递增到n,那可以是int 的i。
while语句
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
int fact=1;
int i=1;
while (i<=n){
fact*=i;
i++;
}
printf("%d\n",fact);
return 0;
}
for 语句
#include <stdio.h>
int main()
{
int n;
scanf("%d",&n);
int fact=1;
int i=1;
for (i=1;i<=n;i++)
{fact*=i;}
printf("%d!=%d\n",n,fact);
return 0;
}
i=1;i<=n;i++
第一个表达式:初始动作
第二个表达式:循环继续的条件
第三个表达式:循环每轮要做的动作
for==while
for语句的流程图
如果有固定次数,用for,比如阶乘
如果必须执行一次,用do while
其它情况用while
第十八个代码 素数
只能被1和自己整除的数,不包括1
2 3 5 7 11 13 17 19
代码
#include <stdio.h>
int main()
{
int x;
scanf("%d",&x);
int i;
int isa=1;// x是素数
for (i=2;i<x;i++)
//i<x意味着i<=x-1,最大的数是x-1
if(x%i==0)
{isa=0;
continue;}
printf("%d\n",i);
if(isa==1)
{printf("是素数\n"); }
else{printf("不是素数");}
return 0;
}
第十九个代码 素数
#include <stdio.h>
int main()
{
int x;
scanf("%d",&x);
for (x=2;x<100;x++){
int i;
int isa=1;// x是素数
for (i=2;i<x;i++)
//i<x意味着i<=x-1,最大的数是x-1
if(x%i==0)
{isa=0;}
printf("%d\n",i);
if(isa==1)
{printf("%d",x); }
else{printf("\n");}
}
return 0;
}
第二十个代码 凑硬币
如何用一角、二角和五角的硬币凑出10元以下的金额呢
#include <stdio.h>
int main()
{
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("可以用%d个1角加%d个2角加%d个5角得到%d元\n",one,two,five,x);
exit=1;break;}
}
if(exit==1)break;}
if(exit==1)break;}
return 0;
}
goto的使用 使用多重循环需要从最里面跑到最外面的时候,才用goto,否则多用的话,就是破坏程序的结构性。
#include <stdio.h>
int main()
{
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("可以用%d个1角加%d个2角加%d个5角得到%d元\n",one,two,five,x);
goto out;
}
}
}
}
out:
return 0;
}
第二十一个代码 用代码算出以下函数
#include <stdio.h>
int main()
{
int n;
int i;
double sum=0.0;
int sign=1;
//scanf("%d",&n);
n=100;
for(i=1;i<=n;i++){
sum+=sign*1.0/i;
sign=-sign;
}
printf("f(%d)=%f\n",n,sum);
return 0;
}
第二十二个代码
第二十三个代码 简单的除法
#include <stdio.h>
int main()
{
float a=34.0;
float b=13.0;
float c;
c=a/b;
printf("%lf",c);
return 0;
}
第二十四个代码 求符合给定条件的整数集
#include <stdio.h>
int main()
{
int a;
scanf("%d",&a);
int i,j,k;
int cnt=0;
// i:index j k是连续下来的
i=a;
while(i<=a+3){
j=a;while(j<=a+3){
k=a;while(k<=a+3){
if(i!=j){
if(i!=k){
if(j!=k){
cnt++;
printf("%d%d%d",i,j,k);
if(cnt==6){
printf("\n");
cnt=0; //将其初始值又变为0
}else{
printf(" ");
}
}
}
}
k++;}
j++;}
i++;}
//printf在最后的话,可以得到三个数字,因为没有经过中间的循环,在中间的话,就可以有很多个。
return 0;
}
第二十五个代码 猜数游戏
#include <stdio.h>
int main()
{
int number,n;
int inp;
int finished=0;
int cnt=0;
scanf("%d %d",&number,&n);
do{
scanf("%d",&inp);
cnt++;
if(inp<0){printf("Game Over\n");finished=1;}
else if(inp>number){printf("Too big\n");}
else if(inp<number){printf("Too small\n");}
else {
if(cnt==1){printf("Bingo!\n");}
else if(cnt<=3){printf("lucky You!\n");}
else{printf("Good Guess!\n");}
finished=1;}
if(cnt==n){
if(!finished){printf("Game Over\n");finished=1;}
}
}while(!finished);
return 0;
}
第二十六个代码 求序列前N次和
本题要求编写程序,计算序列2/1+3/2+5/3+8/5+的前N项之和。注意该序列从第二项起,每一项的分子是前一项分子与分母的和,分母是前一项的分子。
输入格式
输入在一行中给出一个正整数N.
输出格式
在一行中输出部分和的值,精确到小数点后2位。题目保证要求计算结果不超过双精度范围。
输入样例
20
输出样例
32 66
代码
#include <stdio.h>
int main()
{
int n;
double dividend,divisor;
double sum=0.0;
int i;
double t;
scanf("%d",&n);
//n=20000;
dividend=2;
divisor=1;
for(i=1;i<=n;i++){
sum+=dividend/divisor;
t=dividend;
dividend=dividend+divisor;
divisor=t;
}
printf("%.2f\n",sum);
return 0;
}
知识点
数据类型
C语言的变量,必须:在使用前定义;确定类型
C++/Java更强调类型,对类型的检查更严格 JavaScript、Python不看重类型,甚至不需要事先定义
类型安全:支持强类型的观点认为明确的类型有助于尽早发现程序中的简单错误。
C语言的类型
整数 char short int long long long
浮点数 float double long double
逻辑 bool
指针
自定义类型
整数类型
类型名称:int long(int long) double
输入输出时的格式化:%d %ld %lf
所表达数的范围:char<short<int<float<double
内存中所占据的大小:1个字节到16个字节
int就是用来表示寄存器的
1个字节(8个bit)可以表达的数
00000000-11111111(0-255)
1 原码
就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。
+1=00000001 -1=10000001
2 反码
+1=00000001原=00000001反=00000001补
-1=10000001原=11111110反=11111111补
3 补码
正数的补码就是其本身
负数的补码是在其原码的基础上,符号位不变,其余各位取反,最后+1
+1=00000001原=00000001反=00000001补
-1=10000001原=11111110反=11111111补
人们想出了将符号位也参与运算的方法。根据运算法则减去一个正数等于加上一个负数,即1-1=1+(-1)=0,所以机器可以只有加法而没有减法,这样计算机运算的设计就更简单。
看原码的计算
计算十进制的表达式:1-1=0
1-1=1+(-1)=00000001原+10000001原=10000010原=-2 如果用原码表示,让符号位也参与计算,显然对于减法来说,结果是不正确的。这也就是为何计算机内部不使用原码表示一个数。
为了解决原码做减法的问题,出现了反码:
计算十进制的表达式:1-1=0
1-1=1+(-1)=00000001原+10000001原=00000001反+11111110反=11111111反=10000000原=-0
发现用反码计算减法,结果的真值部分是正确的。而唯一的问题其实就出现在“0”这个特殊的数值上,虽然人们理解上+0和-0是一样的,但是0带符号是没有任何意义的,而且会有00000000原和10000000原两个编码表示0
于是补码的出现,解决了0的符号问题以及0的两个编码问题:
1-1=1+(-1)=00000001原+10000001原=00000001补+11111111补=100000000补=00000000补=00000000原 注意:进位1不在计算机字长里。
-1=0-1=00000000(原)-00000001(原)=100000000(补)-00000001(补)=11111111(补)
-a 其补码就是0-a 实际是2n-a,n是这种类型的位数
-1就是100000000 2的8次方-1 -1=255
数的范围
对于一个字节(8位),可以表达的是:00000000-11111111
其中
00000000-0
11111111-00000000 -1-(-128)
00000001-01111111 1-127
char表达的范围是-128-127 一个字节所能表示的数为256个,因为中间有个0,所以是在-128-127
整数越界
整数是以纯二进制方式进行计算的,所以:
11111111+1-100000000-0
01111111+1-10000000 -128
10000000-1-01111111 127
unsigned与否只是输出的不同,内部计算是一样的
浮点类型
float 32(占据四个字节)
double 64(占据8个字节)
%e 就是会输出一个科学计数法
如果没有特殊需要,只使用double
char是一种整数,也是一种特殊的类型:字符。这是因为
用单引号表示的字符字面量:'1'
printf和scanf里用%c来输入输出字符
'1'的ASCII编码是49,所以当c==49时,它代表'1'
逃逸字符
用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠“\”开头,后面跟上另一个字符,这两个字符合起来,组成了一个字符。
printf("如输入\"5 7\"表示5英尺7英寸") 这里的话就是如果单独是一个“就会导致与前面的双引号重合,没有达到想要的目的。
#include <stdio.h>
int main()
{
int main;
printf("123\b\n456\n");
return 0;
}
123
456
#include <stdio.h>
int main()
{
int main;
printf("123\bA\n456\n");
return 0;
}
12A
456
类型转换
自动类型转换
对于printf,任何小于int的类型会被转换成int;float会被转换成double %f会自动输入double 而不用%lf
但是scanf不会 要输入short 需要%hd
强制类型转换
要把一个量强制转换成另一个类型(通常是较小的类型)比如说int 转化成char。需要(类型)值
(int)10.2 把10.2这个double转化成int
注意事项:小的变量不总能表达大的量。比如(short)32768:把32768赋给short 因为short只能表达3276,所以32768在short会被表达为-32768
bool
#include <stdio.h>
#include <stdbool.h>
int main()
{
bool b=6>5;
bool t=true;
t=2;
printf("%d\n",b);
return 0;
}
初见函数
函数是一块代码,接收零个或多个参数,做一件事情,并返回零个
函数头void 返回类型 sum 函数名(int begin,int end) 参数表
{ 括号里面是函数体
int i;
int sum=0;
for(i=begin;i<=end;i++){sum+=i;}
printf("%d到%d的和是%d\n",begin,end,sum);
}
调用函数
#include <stdio.h>
void cheer()
{
printf("cheer\n");
}
int main()
{
cheer();
return 0;
}
下面的int main()调用上面的函数
()起到了表示函数调用的重要作用
即使没有参数也需要()
例子int main()中的cheer()则需要加括号
函数先后关系
#include <stdio.h>
int main()
{
sum(1,10); 编译器就会猜这是 int sum(int int) 但是这里又与后面给的void sum 是冲突的
sum(20,30);
sum(35,45);
void sum(int begin,int end)
{
int i;
int sum=0;
for(i=begin;i<=end;i++)
{sum+=i;}
printf("%d到%d的和是%d\n",begin,end,sum);
}
return 0;
}
假如把先后顺序颠倒之后,编译器就会猜是什么
参数传递
#include <stdio.h>
void cheer(int i)
{
printf("cheer\n");
}
int main()
{
cheer(2.4);
return 0;
}
类型不匹配,编译器会自动转换,比如这里会把2.4转换成2
#include <stdio.h>
void swap(int a,int b);
int main()
{
int a=5;
int b=6;
swap(a,b);(实际参数)
printf("a=%d b=%d\n",a,b);
return 0;
}
void swap(int x,int y) 形式参数
{
int swap;
int t=x;
x=y;
y=t;
}
C语言在调用函数时,永远只能传值给函数 比如把main里的a=5,b=6调到swap中的inta intb
main里的inta intb是不能转到swap里的,虽然它们名称一模一样
每个函数有自己的变量空间,参数也位于这个独立的空间中,和其它函数没有关系
对于函数参数表中的参数,叫做“形式参数”,调用函数时给的值,叫做“实际参数”
本地变量
函数的每次运行,就产生了一个独立的变量空间,在这个空间中的变量,是函数的这次运行所独有的,称作本地变量 定义在函数内部的变量就是本地变量 参数也是本地变量
本地变量是定义在块内的 它的生成与消亡都是在这个块内独自进行的
#include <stdio.h>
void swap(int a,int b);
int main()
{
int a=5;
int b=6;
swap(a,b);
if(a<b){int i=10;}//i就是定义在这个块的变量
printf("a=%d b=%d\n",a,b);
return 0;
}
void swap(int x,int y)
{
int swap;
int t=x;
x=y;
y=t;
}
函数庶事
调用函数时的圆括号里的逗号是标点符号,不是运算符
f(a,b) 逗号
f((a,b)) 运算符
int main()也是一个函数
初试数组
{
int i;
printf("%d\t",cnt);
for(i=0;i<=cnt;i++)
{printf("%d\t",number[i]);}
printf("\n");
}
1 2 3 4 5 6 7 8 9 10
0 1 // 循环的第一轮cnt=0 在number的位置放了一个1
1 1 2
2 1 2 3
3 1 2 3 4
4 1 2 3 4 5
5 1 2 3 4 5 6
6 1 2 3 4 5 6 7
7 1 2 3 4 5 6 7 8
8 1 2 3 4 5 6 7 8 9
9 1 2 3 4 5 6 7 8 9 10
//
#include <stdio.h>
int main()
{
int x;
double sum=0;
int cnt=0;
int number[100];//定义数组
scanf("%d",&x);
while(x!=-1)
{
number[cnt]=x; //对数组中的元素赋值
sum+=x;
cnt++;
scanf("%d",&x);
}
if(cnt>0)
{printf("%f\n",sum/cnt);
int i;
for(i=0;i<cnt;i++)//整个for循环叫做遍历数组
{
if(number[i]>sum/cnt)
{printf("%d\n",number[i]);}//使用数组中的元素 将number中的第i个元素交给printf中来算
}
}
return 0;
}
定义数组
变量名称【元素数量】
int grades[100]
数组
数组是一种容器(放东西的东西),特点是
其中所有的元素具有相同的数据类型
一旦创建,不能改变大小
数组中的元素在内存中是连续依次排列的
#include <stdio.h>
int main(void)
{
const int number=10;//数组的大小
int x;
int conut[number];//定义数组
int i;
for(i=0;i<number;i++){count[i]=0;}//初始化数组
scanf("%d",&x);
while(x!=-1){
if(x>=0&&x<=9){count[x]++;}
scanf("%d",&x);
}
for(i=0;i<number;i++)
{printf("%d:%d\n",i,count[i]);}
return 0;
}
数组例子
判断素数
第一种方法 从2到x-1测试是否可以整除
#include <stdio.h>(这个代码也没有运行起来)
int x;
int main()
{
int x;
scanf("%d",&x);
if(isPrime(x))
{printf("%d是素数\n",x);}
else
{printf("%d是素数\n",x);}
return 0;
}
从2以外,所有的偶数都是素数
去掉偶数后,从3到x-1,每次加2 只需要走n/2遍即可。 如果n是100,只需要走50就可以
已有的素数表,根据这张表确定是不是素数
cnt(count)计数
2 |
下标分别是0123
prime[count++]=i
因为第一个数2 是第一个cnt 所以下一个素数过来的时候,就直接cnt2
因为是求10个素数 所以cnt只需走到10即可 但是i需要走到29
#include <stdio.h>
int isPrime(int x,int knowPrimes[],int numberOfKnownPrimes);
int main(void)
{
const int number=10;
int prime[number]={2};
int count=1;
int i=3;
while(count<number)
{
if(isPrime(i,prime,count))
{prime[count++]=i;}
{
printf("i=%d \tcnt=%d\t",i,count);
int i;
for(i=0;i<number;i++){printf("%d\t",prime[i]);}
printf("\n");
}
i++;
}
for(i=0;i<number;i++)
{
printf("%d",prime[i]);
if((i+1)%5)printf("\t");
else printf("\n");
}
return 0;
}
int isPrime(int x,int knownPrimes[],int numberofKnownPrimes)
{
int ret=1;
int i;
for(i=0;i<numberofKnownPrimes;i++)
{
if(x%knownPrimes[i]==0)
{
ret=0;
break;
}
}
}
运行结果
i=3 cnt=2 2 3 0 0 0 0 0 0 0 0
i=4 cnt=2 2 3 0 0 0 0 0 0 0 0
i=5 cnt=3 2 3 5 0 0 0 0 0 0 0
i=6 cnt=3 2 3 5 0 0 0 0 0 0 0
i=7 cnt=4 2 3 5 7 0 0 0 0 0 0
i=8 cnt=4 2 3 5 7 0 0 0 0 0 0
i=9 cnt=4 2 3 5 7 0 0 0 0 0 0
i=10 cnt=4 2 3 5 7 0 0 0 0 0 0
i=11 cnt=5 2 3 5 7 11 0 0 0 0 0
i=12 cnt=5 2 3 5 7 11 0 0 0 0 0
i=13 cnt=6 2 3 5 7 11 13 0 0 0 0
i=14 cnt=6 2 3 5 7 11 13 0 0 0 0
i=15 cnt=6 2 3 5 7 11 13 0 0 0 0
i=16 cnt=6 2 3 5 7 11 13 0 0 0 0
i=17 cnt=7 2 3 5 7 11 13 17 0 0 0
i=18 cnt=7 2 3 5 7 11 13 17 0 0 0
i=19 cnt=8 2 3 5 7 11 13 17 19 0 0
i=20 cnt=8 2 3 5 7 11 13 17 19 0 0
i=21 cnt=8 2 3 5 7 11 13 17 19 0 0
i=22 cnt=8 2 3 5 7 11 13 17 19 0 0
i=23 cnt=9 2 3 5 7 11 13 17 19 23 0
i=24 cnt=9 2 3 5 7 11 13 17 19 23 0
i=25 cnt=9 2 3 5 7 11 13 17 19 23 0
i=26 cnt=9 2 3 5 7 11 13 17 19 23 0
i=27 cnt=9 2 3 5 7 11 13 17 19 23 0
i=28 cnt=9 2 3 5 7 11 13 17 19 23 0
i=29 cnt=10 2 3 5 7 11 13 17 19 23 29
2 3 5 7 11
13 17 19 23 29
二维数组
int a[3][5] 通常理解是a是一个三行五列的矩阵
指针的使用
指针应用场景一:交换两个变量的值
指针应用场景二:传入的参数实际上是需要保存带回的结果的变量
#include <stdio.h>
void minmax(int a[],int len,int *max,int *min);
int main(void)
{
int a[]={1,2,3,4,5,6,7,8,9,12,13,14,16,17,21,23,55,};
int min,max;
minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);
printf("min=%d,max=%d\n",min,max);
return 0;
}
void minmax(int a[],int len,int *min,int *max)
{
int i;
*min=*max=a[0]; //先让*min=*max=a[]的第一个元素0
for(i=1;i<len;i++) //遍历整个数组
{
if(a[i]<*min){*min=a[i];}
if(a[i]>*min){*max=a[i];}
}
}
运行结果 min=1 max=55
指针应用场景二b:函数返回运算的状态,结果通过指针返回
指针与数组
数组变量就是特殊的指针
数组变量本身表达地址,所以
int a[10];
指针与const
表示一旦得到了某个变量的地址,不能再指向其它变量
转换:总是可以把一个非const的值转换成const的
const 数组
const int a[]={1,2,3,4,5,6}; 这里的1,2,3,4,5是const的
指针运算
#include <stdio.h>
int main(void)
{
char ac[]={0,1,2,3,4,5,6,7,8,9,};
char *p=ac; //p是一个指针,指向数组ac[]的第一个数
printf("p=%p\n",p);
printf("p+1=%p\n",p+1);
int ai[]={0,1,2,3,4,5,6,7,8,9,};
int *q=ai; //p是一个指针,指向数组ac[]的第一个数
printf("q=%p\n",q);
printf("q+1=%p\n",q+1);
return 0;
}
p=000000000065FE00
p+1=000000000065FE01
q=000000000065FDD0
q+1=000000000065FDD4
因为char中占的sizeof是1 而int中占的sizeof是4
*p++
取出p所指的那个数据来,完事之后顺便把P移到下一个位置去
*的优先级虽然高,但是没有++高
0地址
假如用0地址表示某些事情,程序一定会崩溃
null是一个预定定义的符号,表示0地址。而不是用0这个符号
指针的类型
无论指向什么类型,所有的指针的大小都是一样的,因为都是地址
但是指向不同类型的指针是不能直接互相赋值的
指针的作用总结
需要传入较大的数据时用作参数
传入数组后对数组做操作
函数返回不止一个结果(需要用函数来修改不止一个变量)
字符串数组
char **a a是一个指针,指向另一个指针,那个指针指向一个字符(串)
char a[ ][ ]
程序参数
之前说的int main里面是没有什么东西的(),现在在里面加上(int argc,char const*argv[])
putchar:函数来的。顾名思义,将char放到标准框中
EOF(-1)表示写失败
枚举法
枚举是一种用户定义的数据类型,它用关键词enum以如下语法来声明:
enum 枚举类型名字{名字, 名字n}
枚举类型名字通常并不真的使用,要用的是大括号里的名字,因为它们就是常量符号,它们的类型是int,值则依次从0到n.如
enum colors{red,yellow,green} 创建了三个常量 red就是0 yellow就是1 green就是2