C语言笔记
一.初始c语言
该程序的源文件如下: #include<stdio.h>//包含头文件 stdio.h,只有包含了该头文件,才能输出 intmain(void)//主函数,C 程序就是从这里开始运行的 { printf("HelloWorld!\n");//输出语句,双引号里面可以是任意的内容 return0; }
创建 C 程序项目小结: 1>选择 VisualC++,Win32 控制台 2>添加源文件.c,C++源文件.cpp,头文件.h 3>项目文件.sln
一、main 主函数
1.只能有一个主函数,必须要有一个主函数,C 程序从主函数开始运行。 2.intmain(void),int:返回值类型,main:函数名,void:参数
第 10 页 共 130 页
3.return0,返回值是 0。
二.、注释
1.单行注释// 2.多行注释/**/ 注意:不能在多行注释中嵌套多行注释 注释一个函数时通常用多行注释,注释某个语句用单行注释
三、C 程序执行的过程:
编辑---写代码的过程,生成.c 文件 编译---检查语法错误的过程,生成.obj 文件 连接---多个.obj 文件合并成一个.exe 文件的过程 执行---运行.exe 文件的过程
四、C 程序的结构
项目--->文件--->函数--->语句--->单词 项目:后缀是.sln 文件:源文件后缀是.c 函数:可以有多个函数,但一定要有主函数 语句:以分号;结尾 单词:不是单纯的英文单词,而是标识符,标识符又分成:关键字、预定义标识符、自定 义标识符。C 语言的标识符命名规范:由字母、数字、下划线构成且第一个字符不能是数 字,且不能是系统占用的单词。 练习:在程序中分别找出哪些是关键字、预定义标识符、自定义标识符?
第 11 页 共 130 页
------------------------------------PM------------------------------------八、进制的转换 在计算机内存储和运算数据时,通常要涉及到的数据单位有以下 3 种: 位(bit):计算机中的数据都是以二进制来表示的,二进制的代码只有“0” “1”两 个数码,采用多个数码(0 和 1 的组合)来表示一个数,其中的每一个数码称为一位,位 是计算机中最小的数据单位。 字节(Byte):在对二进制数据进行存储时,以 8 位二进制代码为一个单元存放在一 起,称为一个字节,即 1Byte=8bit。字节是计算机中信息组织和存储的基本单位,也是计 算机体系结构的基本单位。在计算机中,通常用 B(字节)、KB(千字节)、MB(兆字节) 或 GB(吉字节)为单位来表示存储器(如内存、硬盘、U 盘等)的存储容量或文件的大小。 字长:人们将计算机一次能够并行处理的二进制代码的位数,称为字长。字长是衡量 计算机性能的一个重要指标,字长越长,数据所包含的位数越多,计算机的数据处理速度 越快。计算机的字长通常是字节的整倍数,如 8 位、16 位、32 位、64 位和 128 位等。
1.内存容量 1TB--->1024GB 1GB--->1024MB 1MB--->1024KB 1KB--->1024Bbyte(字节) 1byte--->8bit(位)
数制是指用一组固定的符号和统一的规则来表示数值的方法。如下图所示为计算机中常用 的几种进位计数制的表示。
2.二进制与十进制的转换
1>将二进制数转换成十进制 10110 转换成十进制数:先将二进制数 10110 按位权展开,再对其乘积相加,转换过程 如下所示。 (10110)2=(1×24+0×23+1×22+1×21+0×20)10 =(16+4+2)10 =(22)10
8421 法(1286432168421) 10111101--->128+0+32+16+8+4+0+1=189
第 12 页 共 130 页
2>将十进制转换成二进制数 除以 2 逆向取余法:
37--->100101 3.二进制与八进制的转换 1>将八进制数转换成二进制:每 1 个八进制位转换成 3 个二进制位,左边不足三个的则补 0。 567--->101110111 234--->010011100
2>将二进制数转换成八进制:从右向左,每 3 个二进制位为一组,每一组转换成 1 个八进 制数。 011010111100110--->32746 011010111101110---32756 011101110101011---35653
4.二进制与十六进制的转换 1>将十六进制数转换成二进制:每 1 个十六进制位转换成 4 个二进制位,左边不足 4 个的则 补 0。 0----0000 1----0001 2----0010 3----0011 4----0100 5----0101 6----0110 7----0111 8----1000 9----1001 A----1010 10 B----1011 11 C----1100 12 D----1101 13 E----1110 14
F----1111 15
1289ADF--->0001001010001001101011011111
2>将二进制数转换成十六进制:从右向左,每 4 个 2 进制位为一组,每一组转换成 1 个十六 进制数。 11101101111110011110--->EDF9E 课堂练习: 1. 请问十进制数 89,二进制数 100111,八进制数 234,十六进制数 1A2 中哪个最大?
五、原码、反码、补码
源码、反码、补码数据在计算机里面都是以补码的形式存储。
原码 反码 补码 37:00100101--->00100101--->00100101 -37:10100101--->11011010--->11011011 正数的原码、反码、补码都是一样的! 负数的反码是在原码的基础上“符号位不变,数值位取反” 负数的补码是在反码的基础上“符号位不变,数值位加 1” 3-2=1 3+(-2)= -2:10000010---11111101---11111110 00000011 +11111110 =00000001 -2:1000000000000010 1111111111111101 1111111111111110
#include<stdio.h>
main()
{
pintf(“hello,world”);
}
各类数值型数据之间的混合运算
变量的数据类型是可以转换的。转换的方法有两种,一种
是自动转换,一种是强制转换。自动转换发生在不同数据
类型的量混合运算时,由编译系统自动完成。自动转换遵
循以下规则:
1)若参与运算量的类型不同,则先转换成同一类型,然后进行运算。
2)转换按数据长度增加的方向进行,以保证精度不降低。如int型和
long型运算时,先把int量转成long型后再进行运算。
3)所有的浮点运算都是以双精度进行的,即使仅含float单精度量运
算的表达式,也要先转换成double型,再作运算。
4) char型和short型参与运算时,必须先转换成int型
符号解释
%d表示按整型数据的实际长度输出数据
%c用来输出一个字符。
%s用来输出一个字符串
%x表示以十六进制数形式输出整数
%f表示输出小数
&&:运算对象不为0则为真
int a = 5;int b = 10;a&&b为真,1为真,0为假
||较之&&基本相反,有一个为真就是真
sizeof(表达式)求表达式的数据类型占据的字节数
大括号括起来的都是复合语句(确信)
递归函数就是函数调用自己,这种情况:A调的B,然而B调用了A,这也算递归
作用域:一个代码空间,变量的使用范围
函数作用域:只在函数中使用、函数的参数和函数体属于函数作用域,函数的返回值和函数名属于文件作用域
文件作用域:定义在外面的,作用的范围是文件作用域,不过范围貌似是只延伸往下
结构体作用域:定义在外面是全局,定义在代码语句块里就在那里面
语句块作用域:复合语句里,内部的语句里面的作用域不可作用在外部
作者:青色的霖 https://www.bilibili.com/read/cv21494965?spm_id_from=333.999.0.0&jump_opus=1 出处:bilibili
二:基本的数据类型
1,常量与变量
A:常量:
定义:不可以被改变的量
分类:
- 整型常量:整数
- 实型常量:
-
-
- 十进制小数形式:由数字和小数点组成
- 指数形式:由于没法区分上下标所以用字母e或E代表以十为底的指数e或E之前必须要有数字,后面必须为整数
-
-
- 字符常量:有两种形式的字符常量
-
-
- 普通字符常量:单引号括起来的一个字符,字符型在内存中存储的是ASCII码形式
- 转义字符:C语言中的特殊字符常量,是以字符\开头的字符序列,参考下图:
-
-
- 字符串常数:例如“ABC”,用双引号把若干个字符括起来,字符串不包括双引号
- 符号常数:用#define指令代表一个常量。例如:#define PI 3.1415926 (末尾不用加分号),使用符号常量可以做到“一改全改”,注意:符号常量不是变量。
- 地址常量:每一个人常量、变量、数组的地址在程序运行期间是不能够改变的,成为地址产量
B:变量
定义:可以被改变的量。要存什么类型的数据就要用什么类型的定义。
变量代表一个有名字、具体特定属性的存储单元,可以存储数据,也就是一个盒子
变量必须先定义后使用
命名规范:见名知意,符合标识符命名规则(只能由字母、数字、下划线开头,不能是关键字,同一个作用域范围内定义的标识符不允许重名)
定义变量格式:;类型 变量名(标识符)
2,基本数据类型:
A:常用的六种基本数据类型:
整型:int
int HP=10//初始化
int age;
age=100;//赋值操作
字符型:char
占1个字节
单个字符:‘a’
多个字符:”avdg”
字符可以和数字之间转化的;ASCII码表
char ch=’a’;
ch=65;//’A’
int a;
a=ch;//隐示转换
ch=(int)ch;//强制转换
单精度浮点型:float
占四字节,精确到小数点后6—7位
双精度浮点型:double
占八字节,精确到小数点后16—17位
长整型:long
短整型:short
3,数据的输入与输出
A:输出
格式占位符: 将输入的数据转化为指定格式进行输出
printf(“格式占位符”,变量);
输出小数时,默认输出小数点后六位,不够则补零,超过则四舍五入。%.2f输出小数点后两位
字符输出:ch=getchar();从键盘上获取一个字符
B:输入
scanf:可视化输入
scanf(“变量1的类型的格式占位符,变量2的类型的格式占位符”,&变量1,&变量2)
字符输出putvhar(ch);
三:运算符和表达式
A:算术运算符
定义:用于算术运算的特殊符号
B,自增自减运算符
前缀:++a或--a 先自增或自减再运算
后缀:a++或a-- 先运算再自增或自减
运算优先级:多个运算符时先计算优先级高的
C:关系运算符
D:逻辑运算符
逻辑与&&
逻辑或||
逻辑非!
E:条件运算符
条件运算符: 表达式1?表达式2;表达式3
表达式1的结果为真,执行表达式2,否则执行表达式3
#include<stdio.h>
Int main()
{
Int a=10;
Int b=2;
- b?a=11:b=11;
printf(“%d\n”,a);
}
F:赋值运算符
+= -= = *= /= %=
G:逗号运算符和强制类型转换
H:位运算符
位运算符:输入十进制数,以二进制数的运算得到结果后,输出十进数
左移:<< 相当于乘以2的n次方,移几位就乘以2的几次方
右移:>> 相当于除以2的n次方,移几位就除以2的几次方
按位非(取反):~ 二进制1变0,0变1 二进制数最高位表示符号位,0整数 1负数
按位或:| 对应位置,有1则为1,否则为0
5|3
5————0000 0101
3————0000 0011
0000 0111
7
按位与:& 对应位置,都为1,则为1,否则为0
5&3
5————0000 0101
3————0000 0011
0000 0001
1
按位异或:^ 相同位置,相同为0,不同为1 按住shift+6
5……3
5————0000 0101
3————0000 0011
0000 0110————结果为6
sizeof();求类型大小的运算符
操作数:一个运算符要用到几个变量计算,比如两个变量计算则用双目运算符
表达式和C语句
四:循环与分支
选择分支结构
A:if选择分支结构
又名if判断语句
if(表达式)如果结果为真就执行语句,否则不执行
{
语句;
}
2.else if
if(表达式)如果表达式成立则执行语句1,否则执行语句2
{
语句1;
}
else否则
{
语句2;
}
if(表达式1)如果表达式1成立则执行语句1,如果表达式1成立且表达式2成立则执行语句2,否则执行语句3
{
语句1;
}
else if(表达式2)
{
语句2;
}
else
{
语句3
}
注意: 如果a=12,一旦满足前面的某一个分支之后,后面所有分支不在判断,也不再执行,直接跳到分支语句的最后。
双目运算符
C=a>b?a:b;
如果a大于b执行a如果小于执行b
代码:
#include <stdio.h>
main()
{
int a=20,b=10,c;
// if(a>b)
// {
// c=a;
// }
// else
// {
// c=b;
// }
// printf("%d",c);
c=a>b?a:b; //相当于上面的语句,简化成一句,这就是三目运算符的作用
printf("%d",c);
}
B:switch多分支结构
Swinth(表达式)
{
case 常量表达式:
case 常量表达式:
case 常量表达式:
…….
default:
break;
}
- 直接进入case判断,判断哪个表达式的值和常量表达式相等
- 如果没有break,一但遇到满足条件的case之后,就会执行后面所有的语句
五.循环结构
1:for循环
for(表达式1;表达式2;表达式3;)
{
语句;
}
表达式1:条件的初始值
表达式2:判断条件
表达式3:判断的条件的值
第一步 执行表达式1,初始化语句,旨在循环开始的时候执行一次
第二步 执行表达式2,判断条件是否成立,执行循环体语句,否则退出循环
第三步 执行表达式3,在进行判断表达式2,执行循环体语句,否则执行表达式,执行表达式3
第四步 重复执行第二步和第三步
for 例题:
求1的乘积家2的乘积+3的乘积···+k的乘积(1+1*2+1*2*3+···*k)
代码:
#include <stdio.h>
main()
{
int i,k,sum=0,ret=1;
scanf(“%d”,&k);
for(i;i<=k;i++)
{
ret=ret+i;
sum+=ret;
}
Printf(”%d”,sum);
return 0;
}
2:for语句的嵌套
#include<stdio.h>
main()
{
int i,j;
第一步:外面for循环满足,
第二步:执行循环里面的for循环且循环结束,然后接着往下输出
第三步:再次判断是否满足外面的for循环
第四步:重复上面的步骤
3:while循环
while(表达式)
{
语句;
}
表达式成立则执行语句,然后在判断表达式是否成立然后再执行
这个会无限输出无法停止是死循环是错误的
可以这样编写代码结束死循环
while(条件表达式)
{
代码块:
}
- 首先判条件表达式是否成立,如果成立则执行代码块,否则退出循环。
注意!while(只能放条件表达式,不能加; )
例题:
用while求0~100之间所有数的和:
1.先分析:
首先找到每一个数
Int a=0;
while(a<=100)
{
}
2.将每一个数相加
Int a=0,b=0;
while(a<=100)
{
b+=a; //就等于:0+1+2+3+4……
a++;
}
printf( “1~100相加的和为:%d”,b);
3.带入到c++为
4:do while循环
do//【强制执行一次,随后判断表达式,正确接着执行错误停止】
{
代码块;
}while(条件表达式);
注意
这里的whule(条件表达式)后面加分号(;)
注意!这里的do while 是先执行后判断条件是否满足,如果满足则继续执行循环,如果不满足则推出循环
例题:
用do…while求0~100的和
代码:
int a=0,b=0;
do
{
b+=a;
a++;
}while(a<=100);//注意这里有分号!!!
printf("1~100相加的和为:%d",b) ;
6.死循环
这串代码会无限循环下面这几行代码导致死循环,所以慎用goto
a:
printf(“###\n”);//标记
goto b;
b:
printf(“\n”);
goto a
//循环中的变量的使用:局部变量只能再当前for循环中进行使用
for循环的变量只能在for循环中使用
可以在for循环里使用上面的a(a=10)不能在for循环体外面使用a
5.跳转语句
for(int i=0;i<100;i++)
{
if(i%2==0)//i是偶数
{
continue;//跳过本次循环,从这里开始下面循环体不在执行,开始新一次的循环
}
printf(“%d\t”,i);
}
//goto
for(int i=0;i<10;i++)
{
goto a;
printf(“*\n”);
}
a:
printf(“###\n”);//标记
goto b;
b:
printf(“\n”);
goto a;
跳转例题:判断一个数是否为素数
代码:
#include <stdio.h>
main()
{
int a,k,n;
printf("输入一位自然数");
scanf("%d",&k);
for(a=2;a<k;a++)
{
if(k%a==0)
{
n=1;
break;
}
}
if(n==1)
{
printf("是素数");
}
else
{
printf("不是素数");
}
return 0;
}
六.一维数组
数组:是相同数据类型的集合。
从0开始
1为什么要有数组
如:现在要统计版里同学的年龄,如果用变量去储存,那么我们需要定义n个变量,定义和管理都很麻烦,这时候就可以用数组来做,就很方便
//普通变量 int a1,a2,a3…. //用数组,简单,快捷,方便。 int[45] |
2数组的定义:
1.数据类型 数组名【数组大小】
2.数据类型:任意类型
3.数组名:合法标识符即可
4.数组大小:只能是常量
5.数组中的每个元素都由【】里面的数值决定
6.定义数组时[]里面的数不能为变量只能为常量
7.使用时[]里面的值可以是常量也可以是变量
8.数组数值不能整体操作
9.数组的每一个元素都是变量,可以被改变赋值
3数组的初始化
初始化类型
1.
int i;
int num[10]={1,2,3,4,5,6,7,8,9,10}’
for(i=0;i<10;i++)
{
Printf(“%d”,num[i]);
}
printf(“/n”);
2.
int i;
int num[10]={1,2}’
for(i=0;i<10;i++)
{
Printf(“%d”,num[i]);
printf(“/n”);
如果数组只初始部分值,则其他元素被初始化为0。
3.int i;
i[10]={0};
将数组所有元素初始化为0.
4.
让地五个元素为5其他为0
代码
#include <stdio.h>
main()
{
int i;
int num[10]={[5]=5};
for(i=0;i<10;i++)
{
printf("%d ",num[i]);
}
printf("/n");
return 0;
}
5.定义时没有告知是几个元素,这个是错误的
int num[];
6.如果定义时,[]中没有值,这个数组的值由{}里面的元素个数决定
int num[]={1,2,3};
4数组的大小
数组的大小=元素个数*每个元素大小
求数组大小
代码:
#include <stdio.h>
main()
{
int i;
int num[10]={1,2,3,4,5,6,7,8,9,10};
printf("%d ",sizeof(num));
printf("/n");
return 0;
}
求数组元素个数:
代码:
#include <stdio.h>
main()
{
int num[10]={1,2,3,4,5,6,7,8,9,10};
int i=sizeof(num)/sizeof(num[0]);//num[0]代表一个元素//int也代表一个元素
printf("%d",i);
}
一共有十个元素
5数组在内存中的地址
数组在内存如和储存
启动一个程序,系统会给这个程序分配一块内存空间。
内存的最小单位是1个字节,每个字节都有每个编号,这个编号我们把它叫内存的地址
数据在内存中的地址,就是它在内存中的起始地址
6一维数组数组名
int a[5]
2.数组的地址和数组名
int a[10]
数组名a,等价于第0个元素的地址(首元素地址)
数组名是常量,不能被赋值
证明
#include <stdio.h>
main()
{
int a[5];
printf("%u\n",&a[0]);
printf("%u\n",a);
printf("%u\n",&a);//这三个相等
printf("%u\n",&a[0]+1);//元素地址+1跨过一个元素
printf("%u\n",a+1);//元素地址+1跨过一个元素
printf("%u\n",&a+1);//整个数组的地址+1跨过整个数组
}
&a[0] 第0个元素的地址
&a 整个数组地址
7强化训练
求一个数组的最大值
#include <stdio.h>
main()
{
//求数组最大值
int a[10] = { 1,15,68,95,68,456,85,12,3,89};//最大值是456
int max = a[0];//定义
int i = 0;//初始化i
for (i; i < 10; i++)//循环
{
if (max < a[i])//判断条件
max = a[i];//判断结果
}
printf("%d", max);
return 0;
}
8数组冒泡排序原理
将数组元素从小到大排列
冒泡:相邻两个元素比较,前面的比后面的大,两元素交换
一共有n个元素,一共比较n-1论=轮,没比较一轮,下一轮少比较一次
9数组冒泡代码的实现
代码:
#include <stdio.h>
main()
{
int a[5] = { 1,5,6,3,-1 };
int n = sizeof(a) / sizeof(a[0]);//求元素的多少
int i = 0;
for (i; i < n - 1; i++)
{
//因为每次比较的次数都要减1,刚好i每次加1,所以每一轮比较的次数是n-1-i
for (int j = 0; j < n - 1; j++)//每一轮需要比较的次数
{
if (a[j] > a[j + 1])//如果前面的元素比后面的元素大,则交换位置
{
int t = a[j + 1];
a[j + 1] = a[j];
a[j] = t;
}
}
}
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
return 0;
}
七.二维数组
1二维数组的定义与使用
二维数组定义的一般形式是:
|
类型说明符 数组名[常量表达式1][常量表达式2]
其中常量表达式1表示第一维下标的长度,常量表达式2表示第二维下标的长度
- 二维数组在概念上是二维的,其下标在两个方向上变化,对其访问一般需要两个下标。
- 在内存中并不存在二维数组,二维数组实际的硬件存储器是连续编址的,也即是说内存中只有一维数组,即放完一行之后顺次放入第二行,和一维数组的存放方式是一样的。
C++ 代码:
#include <stdio.h>
main()
{
int a[3][4]={0};
int i;
int j;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
二维数组每一个元素也是一种变量
//我想让第1行第三个成为‘3’让第2行第4个成为4.
则
从0开始。
2二维数组的初始化
和一维数组一样,给二维数组部分元素初始化,其余为0
a[3][4]一共有12个数三行四列
如果想让他们全部打印,需要用到循环实现
一维数组可以省略[]里面的数
二维只能省略行,列必须写:a[][3]这样可以
二维数组定义时,不能省略列的下标,可以省略行的下标
注意:更改行或者列的时候循环里面的数也要更改
9.scanf输入读取字符串
缺点:遇到空格就会提前结束读取,如果存放读取字符的空间不足,但他也会继续存放,会造成内存污染
\s 从键盘获取一个字符串遇到\n结束,或者遇到空格结束
3求二维数组的行和列
更改行和列的时候,循环里面也更改这样会显的很麻烦所以要查询行和列
如何查询元素个数和行和列呢?
代码:
#include <stdio.h>
main()//求数组的行和列
{
int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
int n = sizeof(a) / sizeof(a[0][0]);//求数组的个数
int hang = sizeof(a) / sizeof(a[0]);//行的个数
int lie = sizeof(a[0]) / sizeof(a[0][0]);//列的个数
printf("数组个数为%d\n 行:%d\n 列:%d\n",n, hang, lie);
}
4.二维数组数组名
不懂看视频:https://www.bilibili.com/video/BV1ud4y1n7EF?t=450.8&p=68
5维数组地址验证
#include <stdio.h>
main()
{
int a[2][3] = { 1,2,3,4,5,6, };
printf("%u\n", &a[0][0]);
printf("%u\n", a[0]);
printf("%u\n", &a);
printf("%u\n", a);
printf("%u\n", &a);
//前4个起始地址是一样的
printf(" %u \n", &a[0][0]+1);
printf(" %u \n", a[0]+1);
printf(" %u \n", &a+1);
printf(" %u \n", a+1);
printf(" %u \n", &a+1);
return 0;
}
6.了解多维数组
多维数组的意思是:2维以上就是多维
比如a[][][]就是多维数组
那如何来表示这个多维数组呢?
先来看看三维数组的初始化
以a[2][3][4]为例
Int a[2][3][4]={
{
{1,2,3}{1,2,3}{1,2,3}
}
{
{2,3,4}{4,5,6}{7,8,9}
}
}
如何打印三维数组
代码:
#include <stdio.h>
main()
{
int num[2][3][4];//定义了一个三维数组意思是有两个二维数组,每个二维数组有三个一维数组,每个二维数组有4个元素
for (int i = 0; i < 2; i++)
{
for (int k = 0; k < 3; k++)
{
for (int j = 0; j < 4; j++)
printf("%d ", num[i][k][j]);
}
}
return 0;
}
不管是几维数组都是相同的写法
7.字符数组
int a[10]这样的是int类型,是数组数组
char b[10]这样的是char类型是字符数组
#include <stdio.h>
main()
{
//int a[10]这样的是int类型,是数组数组
//char b[10]这样的是char类型是字符数组
//字符数组的打印:
char a[5] = { 'a','b','c','d','e' };
for (int i = 0; i < 5; i++)
{
printf("%c", a[i]);
}
return 0;
}
如果打印部分char
后面是显示不出来的
字符数组显示不出来(显示不出来的是\0)但数值数组可以显示
#include <stdio.h>
main()
{
//int a[10]这样的是int类型,是数组数组
//char b[10]这样的是char类型是字符数组
// 字符串就是字符数组中有\0字符的数组
// 因为有\0字符的字符数组,操作起来更方便
//字符数组的打印:
char a[5] = "abcd";//定义了一个字符数组,存的是abcd\0
char[]="worle"//一共有6个元素,多加个\0
//char a[5] = { 'a','b','c' };
char a[5] = { 'a','b','c','d','\0'};//字符数组中含有\0的,它也是字符串
for (int i = 0; i < 5; i++)
{
printf("%c", a[i]);
}
printf("\n");
for (int i = 0; i < 5; i++)
{
printf("%d ", a[i]);
}
return 0;
}
8.字符数组初始化
0,\0,{}区别
#include <stdio.h>
main()
{
char a[5] = { 'a','b','c','d','e' };//写法复杂,但简单
char b[7] = "abcde\0";//这个写法更简便,遇到\0就不会在执行
for (int i = 0; i < 5; i++)
{
printf("%c", a[i]);。
}
printf("\n");
for (int j = 0; j < 5; j++)
{
printf("%c", b[j]);
}
}
在内存里面0和\0是等价的
划横线的地方有乱码,原因是因为没有\0或0
\0最好不要跟一些数字,有可能几个数字连起来刚好是转义字符
//\012相当于\n
10.gets输入读取字符串
库函数,从键盘读取字符串
gets遇到\n结束,遇到空格继续读取空格
#include <stdio.h>
main()
{
//gets遇到\n结束,遇到空格继续读取空格
//gets也会造成内存污染
char a[5] = "";
gets(a);//里面的参数要的是存放读取字符串的地址
printf("[%s]", a);
return 0;
11.fgets读取字符串
库函数,从键盘读取字符串
#include <stdio.h>
main()
{
char num[128]="";
fgets(num, sizeof(num), stdin);//fgets从stdin(标准输入-键盘)读取字符串到"num"数组中,最大可以读sizeof(num)-1取决于你定义了多少数组
printf("%s\n", num);
return 0;
}
fgets标准写法:(定义的数组名,地址(sizeof(数组名)),固定写法:stdin);
遇到空格也会继续执行
sizeof(num)-1取决于你定义了多少数组
fgets会把回车键\n读取
如何将回车键\n去掉呢
11.strlen测有效字符数量
首先我们要知道回车键\n是在最后,但是我们不能删除\n,所以需要将\n替换成0或‘\0’
下面的代码是测有效的字符数量,我们要用他来将\n替换
#include <stdio.h>
main()
{
char num[128] = "hhhh";
int i;
i = strlen(num);
printf("%s\n%d", num, i);
}
如何替换
代码:
#include <stdio.h>
main()
{
char num[128] = "";
fgets(num, sizeof(num), stdin);
num[strlen(num) - 1] = 0;//让最后面的\n=0
printf("%s", num);
return 0;
}
12.字符数组的输出
#include <stdio.h>
main()
{
char num[1024] = "llllll";
printf("%s\n", num);//不光可以这样打印打印
puts(num);//首元素地址,有换行,打印更简便
fputs(num, stdout);//第一个参数,数组首元素地址,用stdout标准输出(屏幕)
}
13.字符串的追加(练习)
将 2中的追加到1中
#include <stdio.h>
main()
{
char num1[128] = "hello";//hello123456
char num2[128] = "123456";
//将num2追加到num1中
int i=0;
while (num1[i] != 0)
{
i++;
}
int j = 0;
while (num2[j] != 0)
{
num1[i] = num2[j];
i++;
j++;
}
puts(num1);
}
八.函数
1.概述:
C语言要求,在程序中用到的所有函数,必须先定义在使用,例如用max函数去求两个数中的大者,必须事先按规范对他进行定义,指定他的名字,函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。这样,在程序执行max时,编译系统就会按照定义所指定的功能执行。如果事先不定义,编译系统怎么知道max是什么,要实现什么功能呢!
定义函数应包括以下几个内容:
- 指定函数的名字,以便以后按名调用。
- 指定函数的类型,及函数返回值的类型。
- 指定函数的参数的名字和类型,以便在调用函数时向他们传递数据。对无参函数不需要这项。
- 指定函数应当完成什么操作,也就是函数是做什么的,及函数的功能。这是最重要的,在函数体中解决的。
C程序是由函数组成的,我们写的代码都是由主函数main()开始执行的。函数 函数是C程序的基本模块,是用于完成特定任务的程序代码单元。
2.分类
从函数定义角度来看,函数可分为系统函数和用户定义函数两种:
- 系统函数,及库函数:这是由编译系统提供的,用户不必自己定义函数可以直接使用它们,比如我们长写的printf()。
- 用户自定义函数:用以解决用户的专门需要。
- 函数的作用
- 函数的使用可以省去重复代码的编写,降低代码重复率。
- 函数可以让程序更加模块化,从而有利于程序的阅读,修改和完善
4.函数的调用:产生随机数
当调用函数时,需要关系5要素:
- 头文件:包含指定文件。
- 函数名字:函数名字必须和头文件生命的名字一样。
- 功能:需要知道此函数能干吗之后才调用
- 参数:参数类型要匹配
- 返回值:根据需要接收返回值
5函数的名字、形参、函数体、返回值
a.函数名:
理论上是可以随便起的名字,最好的名字见名如意,应该让用户看到这个函数就知道函数的的作用和功能。但要注意,函数名后面带括号的(),代表这个函数表示普通变量
b.形参列表:
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形 参。 3.2 形式参数(形参):
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内 存单
元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
在定义函数时指定的形参,在未出现函数调用时,他们并不占内存中的储存单元,因此称他们是形式参数说虚拟参数,简称形参,表示它们并不是实际存在的数据,所以,形参里的变量不能赋值。
在定义函数时指定的形参,必须是,类型加变量的形式:
第一个是对的
第二个只有类型,没有变量
第三个只有变量,没有类型
在定义函数时指定的形参,可有可无,根据函数的需要来设计,如果没有形参,圆括号内容为空,或写一个void关键字:
c.函数体
花括号{}里的内容即为函数体的内容,这里为函数功能 实现的过程,这和原来写代码没有什么区别,以前我们吧代码写在main()函数里,现在只是吧这些写在其他函数里
D.返回值
1.无参无返回值的调用
#include <stdio.h>
//函数的定义不能定义在函数的代码块里,必须在函数的外面定义函数
//符号加()代表这是一个函数
//如果定义的函数没有形参,可以不填,也可以写void,但是如果返回值没有,需要学void
// 函数{}里面的是函数体,所有代码必须放在{}里面
// 函数结束之前需要返回值
// 注意:返回值的类型看函数定义时,所需要的类型
//无参无返回值:
void fun()
{
printf("hello,fun\n");
printf("hello,main\n");
return;
}
main()
{
fun();
return 0;
}
2.有参无返回值的定义和调用
#include <stdio.h>
//定义一个有参五返回值的函数
//函数定义时()小括号里面叫形参,(因为这个形参只是形式上的参数,定义函数时没有给形参开辟空间)
//形参只有被调用时才会分配空间
//形参的定义 类型名+变量名
void fun2(int a,int b)
{
int c;
c = a + b;
printf("a+b=%d\n", c);
return;
}
main()
{
//函数调用有参函数时,不可以不传参
//调用函数时,()里面的参数叫实参
//实参的类型和形参的类型必须一致
//函数调用时,实参的个数应和参数个数相同
//实参为常量,可以为变量,可以为表达式
int x = 3;
int y = 4;
fun2(2,3);//这个是int型的所以要填整数
fun2(x,y);
fun2(x+y,x*y);
}
3.有参数有返回值的调用
#include <stdio.h>
int fun3(int a,int b)//有形参
{
return a + b;
}
int main()
{
//调用有返回值函数时,可以不接返回值,也可以接返回值
//注意!返回的类型是所接收返回值的变量类型也需要是相同
//参数的传递,只能是单向传递(实参传给形参)
int c = fun3(2,3);
printf("a+b=%d", c);
return 0;
}
实参传给形参,形参的值改变不会改变实参的值
以后如果实参是传变量本身,只会是值传递,不会吧变量本身的空间给传进去
//参数的传递,只能是单向传递(实参传给形参)
- 函数的声明
如果使用用户自己定义的函数,而该函数与它是函数(即主函数)不在同一文件中,或者函数定义的位置在主函数之后,则必须在调用此函数之前对被调用的函数作声明。
所谓函数声明,就是在函数尚未在未定义的请况下,
return和 exit的区别
return 结束当前函数
如果return在子函数中调用指挥结束子函数,如果return在main()中,会结束整个程序
exit 是一个库函数,用来结束整个程序
不管exit在哪里调用,都会结束整个程序
exit(0)