[程序设计入门——C语言]笔记,代码-2021.08.20
程序设计入门——C语言 from Shiroki
1.1 计算机和编程语言
计算机语言:程序是用特殊的编程语言洗出来表达如何解决问题的。不是用编程语言和计算机交谈,而是描述它如何做事情的过程或方法。
算法:我们让计算机做计算,就需要像这样找出计算的步骤,然后用编程语言写出来。计算机做的所有事情都叫做计算。
程序的执行:a.解释:接触一个程序,那个程序能试图理解你的程序,然后按照你的要求执行。b.编译:借助一个程序,就像一个翻译,把你的程序翻译成计算机真正能懂的语言(机器语言)写的程序,然后这个机器语言写的程序就能直接执行了。
解释语言VS编译语言:语言本无编译/解释之分,只有常用的执行方式而已。区别在于,解释型语言有特殊的计算能力,但编译型语言有确定的运算性能。
编程语言排名:https://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
1.2 C语言
C语言-B语言-BCPL语言-Fortran
C语言的发展-K&R,也叫经典C
C的发展和版本:
1989-ANSI发布第一个标准:ANSI C
1990-ISO接受ANSI标准:C 89
C的标准在1995年和1999年两次更新:C95和C99
所有当代编译器都支持C99
C语言用在哪里?:操作系统,嵌入式系统,驱动系统,底层系统,图形引擎,图像处理,声音效果
C:编译→运行:需要编辑器,编译器或者IDE(集成开发环境)
1.3第一个程序
使用的软件:Dev C++
第一个C程序:Hello World!
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
程序框架
#include <stdio.h>
int main()
{
return 0;
}
①相加
#include <stdio.h>
int main()
{
printf("23+45=%d\n",23+45);
return 0;
}
②计算找零
#include <stdio.h>
int main()
{
int price = 0;
printf("请输入支付的金额(元):");
scanf("%d",&price);
int change = 100 - price;
printf("找零%d元。\n",change);
return 0;
}
2.1 计算:变量
变量:变量是一个保存数据的地方,当我们需要在程序里保存数据时,就需要一个变量来保存它。用一个变量保存了数据,他才能参加到后面的计算中,比如计算找零。
变量定义:变量定义的一般形式就是:<类型名称><变量名称>
eg:
int price;
int amount;
int price,amount;
变量的名字:变量需要一个名字,变量的名字是一种“标识符”,意思是它是用来识别这个和那个的不同的名字。
原则:标识符只能由字母、数字、下划线组成,数字不可以出现在第一个位置上,C语言的关键字(保留字)不可以用做标识符。
赋值:a=b:将b的值赋值给a。
初始化:当赋值发生在定义变量的时候,就是变量的初始化。C语言是没有强求做初始化,但是所有的变量在第一次被使用的时候(出现在赋值运算符的右边)之前应该被赋值一次。
变量初始化:<类型名称><变量名称>=<初始值>
eg:
int price = 0;
int amount = 100;
组合变量定义的时候,也可以在这个定义中单独给单个变量赋初值,比如:
int price = 0,amount=100;
变量类型:
int price = 0; 定义了一个变量,变量的名字是price,类型是int,初始值是0.
C是一种有类型的语言,所有的变量在使用之前必须定义or声明,所有的变量必须具有确定的数据类型。数据类型表示在变量中可以存放什么样的数据,变量中只能存放指定类型的数据,程序运行过程中也不能改变变量的类型。
读整数:scanf("%d",&price);是要求scanf这个函数读入下一个整数,读到的结果赋值给变量price,小心前面的&
#include <stdio.h>
int main()
{
int a;
int b;
printf("请输入两个整数:");
scanf("%d %d",&a,&b);
printf("%d+%d=%d\n",a,b,a+b);
return 0;
}
#include <stdio.h>
int main()
{
const int AMOUNT = 100;
int price = 0;
printf("请输入金额(元):");
scanf("%d", &price);
int change = AMOUNT - price;
printf("找您%d元。\n", change);
return 0;
}
#include <stdio.h>
int main()
{
printf("请分别输入身高的英尺和英寸,"
"如输入\"5 7\"表示5英尺7英寸:");
double foot;
double inch;
scanf("%lf %lf", &foot, &inch);
printf("身高是%f米。\n",
((foot + inch / 12) * 0.3048));
return 0;
}
2.2计算:数据类型
浮点数:带小数点的数值。浮点本意指的是小数点是浮动的,是计算机内部表达非整数(分数、无理数)的一种方式。另一种方式叫做定点数,不过在C语言中不会遇到定点数。人们借用浮点数这个词来表达所有带小数点的数。
eg:
(foot+inch/12) * 0.3048;
(foot+inch/12.0) * 0.3048;
浮点数和整数放一起运算时,C将整数换成浮点数,进行浮点数运算。
double:双精度浮点数。float:单精度浮点数
数据类型:
整数:int,printf("%d",...),scanf("%d",...)
带小数点的数:double,printf("%f",...),scanf("%lf",...)
2.3 计算:表达式
运算符:指进行运算的动作,比如加法运算符“+”,减法运算符“-”。
算子:指参与运算的值,这个值可能是常数,也可能是变量,还可能是一个方法的返回值。
运算符优先级:
a+b 单目不变,自右向左
a-b 单目取负,自右向左
赋值运算符:赋值也是运算,也有结果
eg:a=6的结果是a被赋予的值,也就是6
a=b=6 → a=(b=6)
嵌入式赋值:不利于阅读,容易产生错误
eg:int a = 6;
int b;
int c = 1+(b=a);
结合关系:一般自左向右;单目+-和赋值=自右向左
eg:
result=a=b=3+c;
result=2;
result=(result=result2)6(result=3+result);
这样的表达式太复杂,不容易阅读和理解,容易造成读程序时的误解。所以要避免写出这样复杂的表达式。这个表达式应该被拆成若干个表达式,然后以明显的正确的顺序来进行计算。
复合赋值:5个算术运算符,+-/%,可以喝赋值运算符=结合起来,形成复合赋值运算符:+=、-=、=、/=、%=,注意两个运算符中间不要有空格
eg:
total+=(sum+100)/2; total=total+(sum+100)/2;
total=sum+12; total=total*(sum+12);
递增递减运算符:++、--。是单目运算符,这个算子还必须是变量。这两个运算符分别是递增和递减运算符,作用是给变量+1或者-1;
count++; count+=1; count=count+1;
前缀后缀:++、--可以放变量前面(前缀形式)也可以放后面(后缀形式)。
a++的值是a+1以前的值,++a的值是加了1以后的值,无论哪个,a自己的值都加了1了。
表达式 | 运算 | 表达式的值 |
---|---|---|
count++ | 给count加1 | count原来的值 |
++count | 给count加1 | count+1以后的值 |
count-- | 给count减1 | count原来的值 |
--count | 给count减1 | count-1以后的值 |
代码联系网站:拼题A,https://pintia.cn/problem-sets?tab=0
3.1 判断与循环:判断
如果:
if(条件成立)
{
...
}
关系运算:对两个数据之间关系的计算
关系运算符:关系运算的结果是一个逻辑值,逻辑值只有两种可能的值:true(真,表示成立)或false(假,表示不成立)。当两个值的关系符合关系运算符的预期时,关系运算的结果为true(1),否则为false(0)。
==相等
!=不相等
大于
=大于或等于
<小于
<=小于或等于
优先级:
1.所有的关系运算符的优先级比算数运算的低,但是比赋值运算的高。
2.判断是否相等的和!=的优先级比其他的低,而连续的关系运算是从左到右进行的。5>36>4,结果是1(true)
注释:以两个斜杠//开头的语句。插入在程序代码中,用来向读者提供解释信息。他们对于程序的功能没有任何影响,但是往往能使得程序更容易被人类读者理解。
/ */注释*:延续数行的注释,要用多行注释的格式来写。多行注释由一对字符序列/开始,以/结束。也可用于一行内的注释。
流程图:
if语句:一个基本的if语句是由一个关键字if开头,跟上在括号里的一个表示条件的逻辑表达式,然后是一对大括号{}之间的若干条语句。如果表示条件的逻辑表达式的结果不是零,那么就执行后面跟着的这对大括号中的语句,否则就跳过这些语句不执行,而继续下面的其他语句。
注意:if这一行结束是没有;的,但是赋值语句是有一个;。这表明这条赋值语句是if语句的一部分,if语句拥有和控制这条赋值语句,决定他是否要被执行。
#include <stdio.h>
int main()
{
const int MINOR = 35;
int age = 0;
printf("请输入你的年龄: ");
scanf("%d", &age);
printf("你的年龄是%d岁。\n", age);
if ( age < MINOR ) {
printf("年轻是美好的,");
}
printf("年龄决定了你的精神世界,好好珍惜吧。\n");
return 0;
}
找零计算器
#include <stdio.h>
int main()
{
// 初始化
int price = 0;
int bill = 0;
// 读入金额和票面
printf("请输入金额:");
scanf("%d", &price);
printf("请输入票面:");
scanf("%d", &bill);
// 计算找零
printf("应该找您:%d\n", bill - price);
return 0;
}
找零计算器2
#include <stdio.h>
int main()
{
// 初始化
int price = 0;
int bill = 0;
// 读入金额和票面
printf("请输入金额:");
scanf("%d", &price);
printf("请输入票面:");
scanf("%d", &bill);
// 计算找零
if ( bill >= price ) {
printf("应该找您:%d\n", bill - price);
}
return 0;
}
找零计算器-特殊情况
#include <stdio.h>
int main()
{
// 初始化
int price = 0;
int bill = 0;
// 读入金额和票面
printf("请输入金额:");
scanf("%d", &price);
printf("请输入票面:");
scanf("%d", &bill);
// 计算找零
if ( bill >= price ) {
printf("应该找您:%d\n", bill - price);
} else {
printf("你的钱不够\n");
}
return 0;
}
计算时间差
#include <stdio.h>
int main()
{
int hour1, minute1;
int hour2, minute2;
scanf("%d %d", &hour1, &minute1);
scanf("%d %d", &hour2, &minute2);
int ih = hour2 - hour1;
int im = minute2 - minute1;
if ( im <0 ) {
im = 60 + im;
ih --;
}
printf("时间差是%d小时%d分。\n", ih, im);
return 0;
}
比大小
#include <stdio.h>
int main()
{
int a,b;
printf("请输入两个整数:");
scanf("%d %d", &a, &b);
int max = b;
if ( a > b ) {
max = a;
}
printf("大的那个是%d\n", max);
return 0;
}
三个数比大小
// max3.c
#include <stdio.h>
int main()
{
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("The max is %d\n", max);
return 0;
}
计算工资
#include <stdio.h>
int main()
{
const double RATE = 8.25;
const int STANDARD = 40;
double pay = 0.0;
int hours;
printf("请输入工作的小时数: ");
scanf("%d", &hours);
printf("\n");
if (hours > STANDARD)
pay = STANDARD * RATE +
(hours-STANDARD) * (RATE * 1.5);
else
pay = hours * RATE;
printf("应付工资: %f\n", pay);
return 0;
}
计算成绩
#include <stdio.h>
int main()
{
const int PASS=60;
int score;
printf("请输入成绩: ");
scanf("%d", &score);
printf("你输入的成绩是%d.\n", score);
if ( score < PASS )
printf("很遗憾,这个成绩没有及格。");
else {
printf("祝贺你,这个成绩及格了。");
printf("再见\n");
}
return 0;
}
3.2判断与循环:循环
if语句可以判断条件是否满足,满足时才做相应的动作,而循环语句可以在满足条件时,不断地重复执行一些动作。
重复执行的语句(循环语句)可以多次执行其他语句,它检查一个逻辑条件是否满足,只在满足的时候执行它的循环体。
while语句是一个循环语句,它会首先判断一个条件是否满足,如果条件满足,则执行后面紧跟着的语句或语句括号,然后再次判断条件是否满足,如果条件满足则再次执行,直到条件不满足为止。后面紧跟的语句或语句括号,就是循环体。
do-while循环和while循环很像,唯一的区别是我们在循环体执行结束的时候才来判断条件。也就是说,无论如何,循环都会执行至少一遍,然后再来判断条件。与while循环相同的是,条件满足时执行循环,条件不满足时结束循环。
数数几位数(4位数以下的数字)
#include <stdio.h>
int main()
{
int x;
int n=1;
scanf("%d", &x);
if(x>999)
{
n=4;
}else if(x>99)
{
n=3;
}else if(x>9)
{
n=2;
}
printf("%d\n",n);
return 0;
}
另一种方式(不限制几位)
#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;
}
if-条件满足才做;while-反复的做
while循环:如果我们把while翻译做“当”,那么一个while循环的意思是:当条件满足时,不断重复循环体内的语句。
循环执行之前判断是否继续循环,所以有可能循环一次也没有被执行;条件成立是循环继续的条件。
do-while循环:在进入循环的时候不做检查,而是在执行完一轮循环体的代码之后,再来检查循环的条件是否满足,如果满足则继续下一轮循环,不满足则结束循环
do
{
<循环语句>
}while(<循环条件>);
比较两种循环:
do-while循环和while循环很像,区别在于,循环体执行结束的时候才来判断条件。也就是说,无论如何,循环都会执行至少一遍,然后再来判断条件。与while循环相同的是,条件满足时执行循环,条件不满足时结束循环。
#include <stdio.h>
int main(){
int x;
scanf("%d",&x);
int n=0;
do{
x /= 10;
n++;
}while(x>0);
printf("%d",n);
return 0;
}
for循环
for循环像是一个计数循环:设定一个计数器,初始化它,然后在计数器到达某值前,重复执行循环体,而每执行一轮循环,计数器值以一定步骤进行调整,比如+1or-1;
for(i=0;i<n;i++):循环n次,循环结束后i的值为n。
for==while:
for(int i=1;i<=n;i++){
fact *= i;
}
int i=1;
while(i<=n){
fact *= i;
i++;
}
for循环:
for(初始动作;条件;每轮的动作){
}
*for中的每一个表达式都是可以省略的。for(;条件;) == while(条件)
小Tips
如果有固定次数,用for
如果必须执行一次,用do while
其他情况用while
4.1 逻辑类型和运算
bool布尔类型:#include <stdbool.h>,之后就可以使用bool,true,false
#include <stdio.h>
#include <stdbool.h>
int main() {
bool b = 6>5;
bool t = true;
t=2;
printf("%d\n",b);
return 0;
}
逻辑运算:逻辑运算是对逻辑量进行的运算,结果只有0或者1.逻辑量是关系运算或逻辑运算的结果。
运算符 | 描述 | 示例 | 结果 |
---|---|---|---|
! | 逻辑非 | !a | 如果a是true结果就是false,如果a是false结果就是true |
&& | 逻辑与 | a&&b | 如果a和b都是true,结果就是true,否则是false |
|| | 逻辑非 | a||b | 如果a和b有一个是true,则结果是true,两个都是false,结果为false |
优先级:!>&&> | |||
短路:逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果,就不会做右边的计算 | |||
eg: | |||
a6&&b1,要是左边是false就不做右边啦 | |||
a==6 | b==1,要是左边是true就不做右边啦 | ||
条件运算:条件,条件满足时的值和条件不满足时的值 | |||
优先级:调减运算符的优先级高于赋值运算符,但低于其他运算符。 | |||
逗号运算符:逗号用来链接两个表达式,并且以其右边的表达式的值作为它的结果。逗号的优先级是所有运算符中最低的,所以他两边的表达式会先计算,逗号的组合关系是自左向右,所以左边的表达式会先计算,而右边的表达式的值就留下来作为逗号运算的结果。 |
4.2 级联和嵌套的判断
猜数字的实现
#include <stdio.h>
int main(){
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("The max is %d\n",max);
return 0;
}
嵌套的判断:当if的条件满足或者不满足的时候要执行的语句也可以是一条if或者if-else语句,这就是潜逃的语句。
if(code == READY)
if(count<20)
printf("一切正常\n");
else
printf("继续等待\n");
else的匹配:else总是和最近的那个if匹配,且缩进格式也不能暗示else的匹配
tips:在if或者else后面总是用{},即使只有一条语句。
级联的if-else if:
if(exp1)
st1;
else if(exp2)
st2;
else
st3;
4.4 循环的例子
计数循环
int count =100;
while (count >=0){
count--;
printf("%d\n",count);
}
printf("发射!\n");
猜数字游戏:让计算机来想一个数,然后让用户来猜,用户每输入一个数,就告诉他是大了还是小了,直到用户猜中为止,最后还要告诉用户他猜了多少次。
注意:因为要让用户重复猜,所以要用循环;在实际写出程序之前,可以先用文字描述程序的思路;核心是循环的条件。
步骤:
1.计算机随机想一个数,记录在number里;
2.一个负责记次数的变量count初始化为0;
3.让用户输入一个数字a;
4.count递增(+1);
5.判断a和number的大小关系,要是a大输入“大”,要是a小输出“小”;
6.如果a和number不相等,程序转回3
7.否则,程序输出“猜中”和次数,然后结束。
#include <stdio.h>
int main() {
// 随机数:每次召唤rand()就得到一个随机的整数
srand(time(0));
// %100:x % n的结果是[0,n-1]的一个整数。
int number = rand()%100+1;
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;
}
4.5 判断和循环常见错误
if语句常见的错误:
忘了大括号:永远在if和else后面加上大括号,即使当时后面只有一条语句;
if后面的分号:是没有滴
错误使用==与=:if只要求()里面的值是0或非0;
使人困惑的else
代码风格:在if和else之后必须加上大括号形成语句块;大括号内的语句缩进一个tab的位置。
5.1 循环控制
素数:只能被1和自己整除的数,不包括1
#include <stdio.h>
int main() {
int x;
//scanf("%d", &x);
x = 12;
int i;
// int isPrime = 1; //X是素数
for(i=2; i<x; i++) {
if(x % i == 0) {
// isPrime = 0;
break;
}
}
// if (isPrime == 1) {
if (i < x) {
printf("是素数\n");
} else {
printf("不是素数\n");
}
return 0;
}
5.2 多重循环
输出100以内的素数
#include <stdio.h>
int main() {
int x;
for(x=2; x<100; x++){
int i;
int isPrime = 1; //X是素数
for(i=2; i<x; i++) {
if(x % i == 0) {
isPrime = 0;
break;
}
}
if (isPrime == 1) {
printf("%d ", x);
}
}
printf("\n");
return 0;
}
嵌套的循环:循环里面还是循环
#include <stdio.h>
int main() {
int x;
x = 2;
int cnt = 0;
// while (cnt < 50) {
// for(x=2; x<100; x++){
for(x=2; cnt<50; x++) {
int i;
int isPrime = 1; //X是素数
for(i=2; i<x; i++) {
if(x % i == 0) {
isPrime = 0;
break;
}
}
if (isPrime == 1) {
printf("%d ", x);
cnt++;
}
// x++; 这里是while循环的地方
}
printf("\n");
return 0;
}
离开多重循环
break和continue:只能对他所在的那层循环做。break跳出内层循环
goto:goto out,直接跳出最外层循环,不要频繁使用
备注:
1.使用while或for循环时,如果想提前结束循环(在不满足结束条件的情况下结束循环),可以使用break或continue关键字。
#include <stdio.h>
int main(){
int i=1, sum=0;
while(1){ //循环条件为死循环
sum+=i;
i++;
if(i>100) break;
}
printf("%d\n", sum);
return 0;
}
while 循环条件为 1,是一个死循环。当执行到第100次循环的时候,计算完i++;后 i 的值为 101,此时 if 语句的条件 i> 100 成立,执行break;语句,结束循环。
在多层循环中,一个 break 语句只向外跳一层。
2.continue 语句的作用:跳过循环体中剩余的语句而强制进入下一次循环。continue语句只用在 while、for 循环中,常与 if 条件语句一起使用,判断条件是否成立。
3.break与continue的对比:break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。
5.3 循环应用
6.1 数组
如何记录很多数?:int num1,num2,num3...?
数字:int number[100]; scanf("%d", &number[i]);
#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++;
printf("请继续输入....\n");
scanf("%d", &x);
}
if (cnt > 0) {
int i;
double average = sum / cnt;
for(i=0; i<cnt; i++) {
if(number[i] > average) { //使用数组中的元素
printf("%d", number[i]); //遍历数组
}
}
}
return 0;
}
定义数组:
<类型> 变量名称[元素数量];
int grades[100];
double weight[20];
元素数量必须是整数
数组:是一种容器(放东西的东西),特点是:
1.其中所有的元素具有相同的数据类型;
2.一旦创建,不可改变大小;
3.数组中的元素在内存中实力按序依次排列的;
例子:int a[10]
10个单元:a[0],a[1]...,a[9]
每个单元就是一个int类型的变量
可以出现在赋值的左边或右边:eg:a[2]=a[1]+6;在赋值左边的叫做左值
数组的单元:数组的每个单元就是数组类型的一个变量
使用数组时放在[]中的数字叫做下标或索引,下标是从0开始计数的。
有效的下标范围:一旦程序运行,越界的数组访问可能造成问题,导致程序崩溃。segmentation fault。
故正确有效的下标范围为:[0,数组的大小-1]
计算平均数
#include <stdio.h>
int main() {
int x;
double sum = 0;
int cnt;
printf("请输入数字的数量:");
scanf("%d", &cnt); //cnt是count的缩写,用做计数器
if (cnt > 0){
int number[cnt];
scanf("%d", &x);
while (x != -1) {
number[cnt] = x;
sum += x;
cnt ++;
scanf("%d", &x);
}
return 0;
}
长度为0的数组:int a[0],可以存在,但是无用。
写一个程序,输入数量不确定的[0,9]范围内的整数,统计每一种数字出现的次数,输入-1表示结束。
#include <stdio.h>
int main() {
const int number = 10; //数组的大小
int x;
int count[10]; //定义数组
int i;
//初始化数组
for(i=0; i<10; i++) {
count[i] = 0;
}
scanf("%d", &x);
while (x != -1) {
if(x >= 0 && x <= 9) {
count[x] ++; //数组参与运算
}
scanf("%d", &x);
}
//数组遍历输出
for (i=0;i<10; i++) {
printf("%d:%d\n",i, count[i]);
}
return 0;
}
6.2 函数的定义和使用
#include <stdio.h>
//把sum这个函数直接提出来到前面
void sum(int begin, int end) { //输入两个形参,int形式
int i;
int sum = 0;
for(i=begin; i<=end; i++) {
sum += i;
}
printf("%d和%d的和是%d\n",begin,end,sum);
}
int main(){
sum(1,10); //调用sum函数,输入1,10两个值,做完之后换到下一行
sum(20,30);
sum(35,45);
return 0;
}
什么是函数:函数是一块代码,接受0个或者多个参数,做一件事情,并且返回0个或者一个值。可以先想成数学中的函数:y=f(x)
调用函数:函数名(参数值);
1.()起到了表示函数调用的重要作用,即使没有参数也是需要()的
2.如果有参数,则需要给出正确的数量和顺序,这些值会被按照顺序依次用来初始化函数中的参数。
函数返回:函数知道每一次是哪里调用它,会返回到正确的地方。
从函数中返回值:拿一个函数距举例
int max(int a, int b)
{
int ret;
if(a > b){
ret = a;
} else {
ret = b;
}
return ret; //这里把ret返回回去了
}
return停止了函数的执行,并且送回了一个值
return 表达式;
一个函数里可以出现多个return语句。
int max(int a, int b)
{
// int ret;
if(a > b){
return a;
} else {
return b;
}
// return ret;
}
而且函数中的返回值可以赋值给变量,可以再传递给函数,甚至还可以丢弃。
没有返回值的函数:
void 函数名(参数表)
1.不能使用带值的return,也可以没有return
2.调用的时候不能做返回值的赋值
注:要是函数有返回值,则必须使用带值的return
6.3 函数的参数和变量
函数先后关系:把函数写在主体语句上面,C的编译器是自上而下的顺序分析代码。在看到sum(1,10)的时候,他需要知道sum()的样子,也就是sum()要几个参数,每个参数的类型如何,返回什么类型,这样他才能检查你对sum()的调用是否正确
函数原型:函数头,以分号结尾,构成了函数的原型。
函数原型的目的是告诉编译器这函数长什么样子:名称,参数(数量和类型),返回类型
eg:
double max(double a, double b); //函数原型
int main() {
int a,b,c;
a = 5;
b = 6;
c = max(10,12);
printf("%d\n", c);
max(12,13); //根据原型判断
return 0;
}
double max(double a, double b); //实际的函数头
旧标准习惯把函数原型写在调用它的函数里面,现在一般写在调用它的函数前面
#include <stdio.h>
void sum(int begin, int end) { //声明一个函数
int main(){
sum(1,10); //调用sum函数,输入1,10两个值,做完之后换到下一行
sum(20,30);
sum(35,45);
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);
}
参数传递:调用函数,如果函数有参数,调用函数的似乎还必须传递给他数量,类型正确的值
可以传递给函数的值是表达式的结果,这包括:字面量,变量,函数的返回值,计算的结果
传值:每个函数都有自己的变量空间,参数也位于这个独立的空间中,和其它函数没关系。过去,对于函数参数表中的参数,叫做“形式参数”,调用函数时给的值,叫做“实际参数”
由于容易让初学者误会实际参数就是在函数中进行计算的参数,误会调用函数的时候把变量而不是值传进去了,所以我们不建议继续用这种古老的方式来称呼他们。
我们认为。,他们是参数和值的关系
本地变量:函数的每次运行,就产生了一个独立的变量空间,在这个空间中的变量,是函数的这次运行所独有的,称作本地变量。定义在函数内部的变量就是本地变量。参数也是本地变量。
变量的生存期和作用域:
1.生存期:什么时候这个变量开始出现了,到什么时候它消亡了
2.作用域:在(代码的)什么范围内可以访问这个变量(这个变量可以起作用)
3.对于本地变量,这两个问题的答案是统一的:大括号内————块
本地变量的规则:
1.本地变量是定义在块内的:他可以定义在函数的块内,也可以定义在语句的块内。甚至可以随便拉一对大括号来定义变量。
2.程序运行进入这个块之前,其中的变量不存在,离开这个块,其中的变量就消失了
3.块外面定义的变量在里面仍然有效
4.快里面定义乐和外面同名的变量则掩盖了外面的
5.不能再一个块内定义同名的变量
6.本地变量不会被默认初始化
7.参数在进入函数的时候被初始化了。
7.1 数组运算
数组的集成初始化:
int a[] = {2,4,6,8,10,3,4,5,6,7,8}
直接用大括号给出数组的所有元素初始值
不需要给出数组大小,编译器替你数数
集成初始化的定位(C99 ONLY)
int a[10] = {
[0] = 2, [2] = 3, 6,
}
用[n]在初始化数据中给出定位
没有定位的数据接在前面的位置后面
其他位置的值补零
也可以不给出数组大小,让编译器算
特别适合初始数据稀疏的数组
数组的大小:sizeof给出整个数组所占据的内容的大小,单位是字节
ziseof(a)/sizeof(a[0])
sizeof(a[0])给出数组中单个元素的大小,于是相除就得到了数组的单元个数
这样的代码,一旦修改数组中初始的数据,不需要修改遍历这样的代码
数组的赋值:
int a[] = {2,4,5,5,2,6,39,2,4,58,78,2,56,5}; √
int b[] = a; ×
注意:数组本身不可以被赋值
要把一个数组的所有元素交给另一个数组,必须采用遍历:
for(i=0; i<length; i++) {
b[i] = a[i];
}
遍历数组:遍历是数据结构中的一种术语。即沿着某条搜索路线,依次对每个元素均做一次且仅做一次访问。所以你要对数组遍历,当然需要你用循环语句,将数组中存放的元素依次输出。
通常都是使用for循环,让循环变量i从0到<数组的长度,这样循环体内最大的i正好是数组最大的有效下标
常见错误是:循环结束条件是<=数组长度,或:离开循环后,继续用i的值来做数组元素的下标!
int main(void)
{
int a[] = {2,4,6,7,1,3,5,9,11,13,23,14,32};
int x;
int loc;
printf("请输入一个数字:");
scanf("%d", &x);
loc=search(x, a, sizeof(a)/sizeof(a[0]));
if (log != -1) {
printf("%d在第%d个位置上\n", x, loc);
} else {
printf("%d不存在\n", x);
}
return 0;
}
数组作为函数参数时,往往必须再用另一个参数来传入数组的大小
数组作为函数的参数时:
不能在[]中给出数组的大小;
不能再利用sizeof来计算数组的元素个数!
8.1 指针
sizeof 是一个运算符,给出某个类型或者变量在内存中所占据的字节数
sizeof(int),sizeof(i)
运算符&:scanf("%d", &i)里面的&,目的是获得变量的地址,它的操作数必须是变量
int i; printf("%x", &i);
地址的大小是否与int相同取决于编译器
int i;printf("%p", &i);
&不可以取地址?:&(a+b) ×
分配内存:自顶向下
相邻数组单元永远相差4
Q:如果能够将取得的变量的地址传递给一个函数,能否通过这个地址在那个函数内访问这个变量?
scanf("%d", &i);
scanf()原型应该是怎样的?我们需要一个参数能保存别的变量的地址,如何表达能够保存地址的变量?
指针:就是保存地址的变量
int i;
int* p = &i;//p指向了i
int* p,q; //p是point指针,但是q只是int类型的一个数
指针变量:变量的值是内存的地址,普通变量的值是实际的值;指针变量的值是具有实际值的变量的地址
作为参数的指针:
void f(int* p);// 在被调用的时候得到了某个变量的地址:int i = 0;f(&i);
在函数里面可以通过这个指针访问外面的这个。
#include <stdio.h>
void f(int *p);
int main(void) {
int i = 6;
printf("&i=%p\n", &i);
f(&i);
return 0;
}
void f(int *p){
printf("p=%p\n", p); //把i的指针p传递给函数,输出的值一致
}
访问那个地址上的变量【*】:
是一个单目运算符,用来访问指针的值所表示的地址上的变量
可以做右值,也可以做左值
int k = p; //读这个值
p = k+1; //写这个值
p可以看做一个整数,其实就代表了那个i,而p是指针,p指向了i
数组变量是特殊的指针:
数组变量本身表达地址,所以:
1.int a[10]; intp=a; //无需用&取地址
2.但是数组的单元编导的是变量,需要用&取地址
3.a == &a[0]
4.[]运算符可以对数组做,也可以对指针做:p[0]<==>a[0]
5.运算符可以对指针做,也可以对数组做:a=25;
6.数组变量是const的指针,所以不能被赋值:int a[] <==> int const a=...
字符类型:char是一种证书,也是一种特殊的类型:字符。这是因为:用单引号表示字符字面量:'a','1'
"也是一个字符
printf和scanf里用%c来输入输出字符
posted on 2021-08-25 10:37 Sihroki初号机 阅读(357) 评论(0) 编辑 收藏 举报