//4.17第一次增补
//4.18第二次增补
//4.19第三次增补
//4.20第四次增补
//4.21第五次增补
//4.23第六次增补
//4.24第七次增补
//注意:使用Markdown表示二维数组使用两个[]会出现歧义,表示指针使用*会出现斜体。 已均在符号前加/来处理这种歧义。//
C语言语法
1. 32个关键字
ANSI C一共只有32个关键字,9种控制语句,关键字全小写,不可被重新定义
1.1 数据类型(12个)
int,char,float,double,enum,long,short,signed,unsigned,struct,union,viod
1.2 控制语句(12个)
for,do,while,break,continue,if,else,goto,switch,case,default,return
1.3 存储类型(8个)
auto,extern,register,static,const,sizeof,typedef,volatile
2. 有符号数和无符号数(计算机默认有符号数)
计算机以补码的形式储存数据,正数的反码和补码是本身,补码的补码是原码
signed:数值有正负之分,以补码的形式存储,最高位是符号位,正数是0,负数是1
例:-10
原码:1000 1010
反码(除符号位取反):1111 0101
补码(反码加1):1111 0110
unsigned:只有正数
为什么取值范围负数总是比正数大?
这里有一个0值的差别。
以最简单的单字节char型为例。占8位,最高位为符号位。
这样0值就有了两种。
0000 0000 (正零)
1000 0000 (负零)
从数学角度上,是没区别的,可是用两种形式表示一个数,明显是浪费了。于是计算机存储就约定,当符号位为0,即正零时才是0.符号位为1时,让它去表示另外一个数好了。
那这个数是什么呢,按照补码的方式求一下,
1000 0000首先符号位为1,是个负数,
取反,0111 1111
加一,1000 0000
又回来了… 但这时代表的就是值了,注意这里的1已经不是符号位了。计算其值就是128.
于是 1000 0000就表示成了-128。
3. 标识符命名规则
(1)只能由字母、数字和下划线组成,不能有空格,且以字母或下划线开头。
(2)C语言的关键字不能用作变量名。
<u> temp 可缩写为 tmp; //temp是“临时”的意思
flag 可缩写为 flg; //flag是“标志位”的意思
statistic 可缩写为 stat; //statistic是“统计”的意思
increment 可缩写为 inc; //increment是“增量”的意思
message 可缩写为 msg; //message是“消息”的意思</u>
4. 数据类型
4.1 基本数据类型
4.1.1 整型(15,66,945,-66)
整型变量:
类型 | bit数 | 取值范围 |
---|---|---|
[signed] int | 32 | -231~231-1 |
[unsigned] int | 32 | 0~232-1 |
[signed] short [int] | 16 | -215~215-1 |
[unsigned] short [int] | 16 | 0~216-1 |
[signed] long [int] | 32 | -231~231-1 |
[unsigned] long [int] | 32 | 0~232-1 |
64位系统long是64bit,32位long是32bit
整型常量(默认有符号):
在整型常量结尾加上“L”或“l”代表长整型,“U”“u”代表无符号
八进制整数(以0做前缀开头):010 0347 -0432
十进制整数
十六进制整数(以0x做前缀开头):0x02 0x33ff
4.1.2 实型(26.2,5.3,2.0,6.593)
有效位数表示包括整数部分的全部数字总数,超出有效位数以近似值储存
实型变量:
类型 | bit数 | 有效数字 | 取值范围 |
---|---|---|---|
float | 32 | 6~7 | -3.4*10-38~3.4*1038 |
double | 64 | 15~16 | -1.7*10-308~1.7*10308 |
long double | 64 | 18~19 | -1.2*10-308~1.2*10308 |
实型常量:
十进制表示:0.0 0.25 3.14 6.0 -6.3
指数形式: 3.0e5 -6.5e18
4.1.3 字符型
字符变量(8bit):类似整型变量,取值范围小
[signed] char = 1000 0000 ~ 1111 1111 (-128 ~ 127)
unsigned char a = 260; //4 (超范围循环计算) (0~255)
[signed] char b = 130; //-126
字符常量:单引号引起来的非字符串,一个字节
非转义字符:'a','num','jingyan'
转义字符:
4.1.4 字符串常量(“CHINA” “yes&no”)
一对双引号括起来的一串字符,字符串不能是双引号(“”)和(\),字符串以’\0’作为结束符。
4.1.5 指针
4.2 define定义常量(宏定义)
#define 符号名 替换列表
#define MSG "HELLO WORLD!"
#define PI 3.14159
#define BEEP "\a"
注意:define实际上是一个预处理命令,只是进行符号替换,不会考虑运算符,需要给每个形参和整体带括号
例:
#define ADD(a,b) a*b
1+ADD(1,2)*2=5
ADD(1+2,3)=7
4.3 定义变量(变量的声明语法为: 储存类型 数据类型 变量名;)
只要定义,就会分配内存空间
存储类型:决定了开辟的空间在内存中的哪个分区(局部变量不写默认auto,全局变量不写就是没有)
数据类型:决定了要开辟的内存空间的大小
变量名:开辟的空间的名字
4.3.1 局部变量
定义在函数体内部的变量
4.3.2 全局变量
定义在函数体外的变量
4.4 储存类型
存储类型:auto,extern,static,register
auto:修饰的变量存储在栈区,只能修饰局部变量
extern:修饰的变量存储在静态区(.bss和.data统称为静态区),只能修饰全局变量
static:修饰的变量存储在静态区,局部变量和全局变量都可以修饰
register:修饰的变量存储在寄存器中,只能修饰局部变量,变量存储在寄存器,可以提高程序的运行速度
(1)除了static和register修饰的局部变量外,其他的都存在栈区
(2)全局变量存储在静态区,没有初始化其默认值为0
(3)局部变量没有初始化其默认值为随机值 (64位操作系统优化为0)
(4)静态变量存储在静态区
生命周期:从什么时候开辟空间到什么时候释放空间
作用域:使用的范围
4.4 复合数据类型
数组
结构体
标识符:struct
共用体
标识符:union
枚举型
标识符:enum
5.数据类型转换
5.1 自动类型转换
(1)横向的转换时必定的,不论运算对象是否为不同类型。
(2)若参与运算量的类型不同,则先转换成同一类型,然后进行运算
(3)转换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量转成long型后再进行运算。
a、若两种类型的字节数不同,转换成字节数高的类型。
b、若两种类型的字节数相同,且一种有符号,一种无符号,则转换成无符号类型,例:比较signed(-1)和unsigned(2),因为signed(-1)=4294967295>2,所以signed(-1)>unsigned(2)
(4)所有的浮点运算都是以双精度进行的,即使是两个float单精度量运算的表达式,也要先转换成double型,再作运算。
(4)char型和short型参与运算时,必须先转换成int型。
(6)在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将转换为左边量的类型。
5.2 强制类型转换
强制类型转换一般格式为:(类型名) 表达式
强制类型转换操作并不改变操作数本身
6. 运算符
6.1 算术运算符:+,-,*,/,%
(1)“/”:当除数和被除数都是整数时,结果自动取整,舍弃小数;当除数和被除数只要有一个浮点数,则进行浮点数相除
(2)“%”:取余不能有浮点数。
(3)自加自减运算符:++在前:++a,先自加,再赋值;++在后:a++,先赋值,再自加。
6.2 赋值运算符:+=,-=,*=,/=,%=,&=,|=,^=,>>=,<<=
6.3 位运算符:&,|,^,<<,>>,~
(1)“&”:有0为0
(2)“|”:有1为1
(3)“^”:相同为0,相反为1
(4)“<<”(左移)、“>>”(右移):如a=a<<2;
<1>逻辑移位,不考虑符号,右移后,左边用0填充。
<2>算术移位(连同符号位一起移),右移后,左边用原数值符号位填充,如果为负,左边全为1;如果为正,左边全为0。负数操作的是补码
<3>算术左移和逻辑左移结果相同。
(5)“~”:取反运算
6.4 关系运算符:>,>=,<,<=,==,!=
(1)关系表达式的值只有“真”和“假”,用“1”和“0”表示。一般来说,0为假,非0为真。
(2)连用关系符有时并不能表示原意。例:a=-1; if(0<a<5)表达式相当于if(0<5),结果为真。
(3)建议常数写在等号左边,如9==a,以防止写出9=a,及时发现错误。
6.5 逻辑运算符:&&,||,!
&&有一个为假则为假,||有一个为真则为真,&&和||截断法则:多个表达式进行逻辑运算,只要前面的可以判断出结果则后面不运算。例:0&&i=3;3没有赋值给i。
6.6 条件运算符(唯一的3目运算符):?:
表达式1?表达式2:表达式3
判断表达式1的值是否成立,如果成立,将表达式2的值作为整个表达式的值,否则,将表达式3的值作为整个表达式的值。
6.7 逗号
表达式1,表达式2,表达式3,………………表达式n
整个逗号表达式的值等于表达式n的值。
例:int a=3,b=5;
int d=(a++,++b);
则a,b,c的值为4,6,6。
6.8 sizeof操作符
求变量占用内存的字节数,sizeof(<类型或变量名>)。
7. 输入和输出
7.1 printf函数
格式字符 | 意义 |
---|---|
a, A | 以十六进制形式输出浮点数(C99 新增)。实例 printf(“pi=%a\n”, 3.14); 输出 pi=0x1.91eb86p+1。 |
d | 以十进制形式输出带符号整数(正数不输出符号) |
o | 以八进制形式输出无符号整数(不输出前缀0) |
x,X | 以十六进制形式输出无符号整数(不输出前缀Ox) |
u | 以十进制形式输出无符号整数 |
f | 以小数形式输出单、双精度实数 |
e,E | 以指数形式输出单、双精度实数 |
g,G | 以%f或%e中较短的输出宽度输出单、双精度实数 |
c | 输出单个字符 |
s | 输出字符串 |
p | 输出指针地址 |
lu | 32位无符号整数 |
llu | 64位无符号整数 |
flags(标识) | 描述 |
---|---|
- | 在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。 |
+ | 强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。 |
空格 | 如果没有写入任何符号,则在该值前面插入一个空格。 |
# | 与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。 与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。 与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。 |
0 | 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。 |
(number) | 要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。 |
.number | 对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。 对于 e、E 和 f 说明符:要在小数点后输出的小数位数。 对于 g 和 G 说明符:要输出的最大有效位数。 对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。 对于 c 类型:没有任何影响。 当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。 |
0 | 在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。 |
h | 参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。 |
l | 参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。 |
L | 参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。 |
7.2 scanf函数
(1)scanf中尽量不要加修饰语,否则就要原样输入。
(2)需要输入多个变量时,一般以空格、TAB或回车做为分隔符,全部输入后用回车做截止符。
(3)使用“%c%c”赋值,不能输入空格、回车、TAB,这些也算字符。可使用%*c来解决问题,*是抑制符。
7.3 字符的输入和输出函数getchar、putchar
此函数是以字符对应的ASCII码做返回的。
7.4 字符串的输入和输出函数gets、puts
(1)①gets只以回车作截止符。
②当字符串的输入结束后,会自动清空缓冲区内容,而scanf会遗留空格、TAB和回车。
③gets首先会检查缓冲区是否有内容,如果有则直接使用,而scanf只能通过键入输入。
(2)puts会自动追加换行符“\n”。
8. 程序结构和语句
三大基本结构:顺序结构、选择结构和循环结构
8.1 顺序结构
按序执行
8.2 选择结构
8.2.1 单分支选择语句
if(表达式)
{
语句;
}
8.2.2 双分支选择语句
if(表达式)
{
语句1;
}
else
{
语句2;
}
8.2.3 多分枝选择语句
(1)if语句
if(表达式)
{
语句1;
}
else if
{
语句3;
}
else if
{
语句4;
}
else
{
语句5;
}
(2)switch语句
switch(表达式)
{
case 标号1:
语句1;
case 标号2:
语句2;
…………
case 标号n:
语句n;
default:
语句n+1;
}
(1)表达式必须是整型或字符型不能是浮点型。
(2)标号必须为常量。
(3)表达式=标号时,执行冒号后面的语句,直到switch,case语句结束,或者碰到break语句结束,所有的标号都不等于表达式时,执行default
例:
8.3 循环结构
8.3.1 for循环语句
先执行表达式1的值,再执行表达式2的值,如果表达式2的值为真,执行循环体,然后执行表达式3的值,如此反复,直到表达式2的值为假,跳出循环。
表达式1,2,3都是可以省略的,但是分号不能省略。2省略为死循环。
for(表达式1;表达式2;表达式3)
{
循环体;
}
8.3.2 while循环语句
表达式的值只要成立,则执行循环体。
while(表达式)
{
循环体;
}
do
{
循环体;
}while(表达式);
8.3.3 转向语句
(1)break语句
break跳出switch语句或跳出本层(1层)循环语句
(2)continue语句
结束本次循环,并不跳出本层循环
(3)goto语句
无条件跳转语句,一般格式为goto语句标号
9. 数组
一组数据类型相同、地址连续的元素的集合。
9.1 定义
存储类型 数据类型 数组名[元素的个数];
(1)数组名代表整个数组。
(2)数组名也代表数组首元素的地址。
(3)元素的个数=sizeof(数组名)/sizeof(数据类型)
9.2 初始化
(1)局部数组不初始化,数组元素值不确定。
(2)static和全局数组不初始化,元素值默认为0。
(3)全部初始化
若想对数组全部元素赋值,数组下标可省略:
int a[5]={1,3,6,5,2};
int a[]={1,3,6,5,2};
不可换行写,如下写法错误:
int a[5];
a[5]={1,5,3,96,2};
(4)部分初始化
当{}中的值少于元素个数时,只给前面部分的元素赋值,后面的自动赋0。
int a[6]={1,3,5};
(5)全部初始化0
int a[10]={0};
int a[] = {0};//表示你这个数组中只有一个元素,没有意义,但是正确的。
9.3 字符数组
9.3.1 定义
本质是字符串,以“\0”结尾。
char c[3]={“ab”};相当于char c[3]={‘a’,‘b’,‘\0’};
9.3.2 输入输出
(1)输入输出切记不能越界。
(2)可以使用scanf函数和printf函数输入输出,使用“%s”,表示处理字符串,取地址可以直接用数组名表示。连续使用时需在中间加上getchar();吃掉每次scanf的回车。
(3)也可使用gets和puts来输入输出。
9.3.3 字符串处理函数
(1)求字符串长度函数strlen(数组)
头文件:string.h
函数原型:size_t strlen(const char *s)
参数:s为字符串
功能&返回值:字符串的长度(不含字符串结束标志“\0”)
strlen和sizeof的区别:
①strlen是求得的字符串的实际长度,不包含’\0’,而sizeof求得的是整个空间的大小。
②sizeof是运算符,strlen是库函数。
(2)字符串拷贝函数strcpy(目标数组1,原数组2)
头文件:string.h
函数原型:char *strcpy(char *dest, const char *src)
功能:字符串拷贝(含字符串结束标志“\0”),所以目标数组要比原数组空间大
参数:src为原字符串的起始地址,dest为目标字符串的起始地址
返回值:目标字符串的起始地址
strncpy(数组1,数组2,n)
功能:将数组2前n个字符拷贝到数组1中
(3)字符串连接函数strcat(目标数组1,原数组2)
头文件:string.h
函数原型:char *strcat(char *dest, const char *src)
功能:将字符串src连接到字符串dest的后面(覆盖\0开始)
参数:src为原字符串的起始地址,dest为目标字符串的起始地址
返回值:目标字符串的起始地址
strncat(数组1,数组2,n)
功能:将数组2前n个字符连接到数组1中
(4)字符串比较函数strcmp(字符串1,字符串2)
头文件:string.h
函数原型:char *strcmp(char char *s1, const char *s2)
功能:按照ASCII码顺序比表字符串s1和字符串s2大小
参数:s1,s2为字符串的起始地址
返回值:
s1=s2,返回值=0
s1>s2,返回值>0
s1<s2,返回值<0
9.4 二维数组
本质:表示元素为连续的一维数组的数组
9.4.1 定义
存储类型 数据类型 数组名[行数][列数];
9.4.2 初始化
(1)降维按行初始化,每一组的初始值都用{}括起来,字符串是“”
int a[2][3] = {{1,2,3},{4,5,6}}; //全部初始化
int a[3][3] = {{1},{4}}; //第一行1 0 0,第二行4 0 0
char a[5][20] = {“xian”, “chengdu”, “beijing”, “lasa”, “hangzhou”} //第一行是xian\0,第二行是beijing\0……
(2)按线性存储的方式赋值
int a[2][3] = {1,2,3,4,5,6};
int a[2][3] = {1,2}; //只有第一行是1 2 0,其他全是0
(3)省略下标的方式
int a[][3] = {{1,2,3}{4,5,6}};
第一位的长度可以省略,第二维的长度不能省略
9.4.3 输入和输出
(1)数值数组:
int a[3][4];
int i, j;
for (i=0; i<3; i++)
for(j=0; j<4; j++)
scanf(“%d”,&a[i][j]); //输入
for (i=0; i<3; i++)
for(j=0; j<4; j++)
printf("%d ",\[i]\[j]); //输出
printf("\n")
(2)字符串数组:
char str[5][20];
int i;
for (i=0; i<5; i++)
scanf(“%s”, str[i]); //输入
for (i=0; i<5; i++)
printf("%s ", str[i]); //输出
10. 指针
10.1 指针基础
内存单元的地址称为指针,存放地址的变量称为指针变量。
10.1.1 指针定义
存储类型 数据类型 *指针变量名; int *p;
存储类型:auto,extern,static,register
数据类型:数据类型表示本指针变量所指向的变量的数据类型
“*”表示一个指针变量类型,变量名即为定义的指针变量名
p ———— 指针变量,它的内容是指向的地址量
*p ———— 指针所指向的对象,它的内容是指向的地址的数据值
&p ———— 指针变量占用的储存地址,是常量。
在32位系统,所有的指针占4个字节,64位系统占8个字节。
10.1.2 指针变量的赋值
char *p = &a;
char *p = NULL;
p = &a;
10.1.3 空指针与野指针
空指针指的是指针变量存了零号地址,在程序中可以为指针赋零。野指针就是未知指向的指针变量。
int *p = 0; //空指针
int *p = NULL; //空指针
int *p; //野指针
指针变量不能修改指向的常量内容。
访问零号地址储存的值或修改其值都不允许!!!野指针指向非法内存,对非法内存的访问是危险的!!!所以将指针设置为NULL是好习惯。
10.2 指针的运算
运算 | 含义 |
---|---|
p+n | 表示指针p向高地址端移动n个数据 |
p-n | 表示指针p向低地址端移动n个数据 |
p++ | 先引用p,再将指针p向高地址端移动1个数据 |
++p | 先将指针p向高地址端移动1个数据,再引用p |
p– | 先引用p,再将指针p向低地址端移动1个数据 |
–p | 先将指针p向低地址端移动1个数据,再引用p |
p-q | 两个指针之间相隔数据元素的个数 |
移动n个数据相当于p + sizeof(指向的数据类型)*n。 |
10.3 多级指针
10.3.1 多级指针定义和引用
一个指向指针变量的指针变量称为多级指针变量。对指向处理数据的指针变量称一级指针,指向一级指针的指针变量称二级指针。
二级指针的形式:
<存储类型> <数据类型> **<指针名>
*q相当于一级指针,得到的是q的目标,即变量p(&m)。**q相当于int类型,可以得到变量m的值。不可令q=&&m,&m是个常量。
10.4 指针与数组
数组指针是指向数组起始地址的指针,本质为指针。
10.4.1 指针与一维数组
(1)数组名代表了数组的起始地址,是常量不能给常量赋值(自加自减)。
(2)p[i]、*(p+i)、*(a+i)、a[i]具有相同的含义,代表数组第i+1个元素。
10.4.2 指针与二维数组
(1)二维数组名参与运算时以行为单位移动,因此被称为行地址。a[0](&a[0][0])就是一维数组名,代表第一行第一列元素的地址,参与运算时以元素单位进行移动。
(2)a[1]等价于*(a+1)。这里的*修饰行地址,将行地址转换成了列地址(相当于行地址中存着每一个元素的地址,列地址就是某一个元素的地址)。总结起来,第二行第一列元素的地址可以表示为:&a[1][0]、a[1]和*(a+1)。
**(3)不可以将某一个元素的地址赋给二维数组的指针(数据类型不同),所以只能p = &a[1];或p = a;(对列地址取地址就是行地址)
存储行地址的指针变量,叫做行指针变量。形式如下:
<存储类型> <数据类型> (*<指针变量名>)[表达式];
例如,int a[2][3];int (*p)[3];
10.5 指针数组
10.5.1 指针数组定义及初始化
指针数组是指由若干个具有相同存储类型和数据类型的指针变量构成的集合。形式如下:
<存储类型> <数据类型> *<指针变量数组名>[<大小>]
例:int *p[2]; p[0] = &m; p[1] = &n; //含有两个元素的一维数组,每个元素都是一个一级指针。
char *n[9];
注意,与行指针的区别在与没有(),这是由于“[]”的优先级高于“*”,因此先和“[]”结合,构成数组的形式。指针数组名就表示该指针数组的存储首地址。
对于例一,p[0]指向m,p[1]指向n;若取得m的值,可以用*p[0]或**p,取得n的值,可以用*p[1]或**(p+1)。
10.5.2 理解指针数组名
对于指针数组的数组名,也代表数组的起始地址,也是首元素的地址。由于数组元素是指针,因此数组名是指针的地址,是多级指针。
比如指针数组int* p[N];数组名p代表&p[0],p[0]是int *,则&p[0]就是int **。若用指针存储数组的起始地址p或&p[0],可以这样用:int **q = p。
10.6 const与指针
const修饰非指针变量时,可以使变量常量化,不可直接修改,只可通过指针间接修改。
10.6.1 常量化指针目标
常量化指针目标限制通过指针修改目标的数值。形式如下:
const <数据类型> *<指针变量名> [=<指针运算表达式>] //const int *p;
10.6.2 常量化指针变量
常量化指针目标使指针指向不能修改。形式如下:
<数据类型> *const <指针变量名> =<指针运算表达式> //int *const p;
10.6.3 常量化指针变量及其目标
常量化指针变量及其目标使指针指向及其指向的变量值都不能改变
const <数据类型> *const <指针变量名> =<指针运算表达式> //const int *const p;
11. 函数
函数就是一个能完成特定功能的代码模块。使程序模块化、可复用性。
11.1 函数的定义
<存储类型><数据类型> <函数名称>(<形式参数列表>)
{
语句序列;
return[(<表达式>)];
}
存储类型:auto,static,extern,register
数据类型:整个函数返回值的类型
函数名称:见名知意
形参列表:实现功能所需的参数,需要调用时传入(几个、类型)
返回值:被调用函数返回给调用函数的值
11.2 函数的调用、传参、返回值
函数名(实际参数列表);
形参指的是出现函数定义中的参数列表;实参出现在主调函数中,调用时,将实参的值传给形参。
①实参和形参在数量上、类型上、顺序上应该严格一致。
②实参可以是变量,常量,表达式、函数,但必须是一个确定的值
③实参和形参是俩块独立的内存空间,形参是局部变量,只在被调用时分配内存,结束即释放。
④参数的传递相当于拷贝。如想要用过对形参的操作来影响实参的值,则可传递变量的地址。
函数的返回值:
return (表达式);
①函数每次调用只能有一个return语句被执行,因此只能有一个返回值。
②返回值若和函数定义的类型不同则自动类型转换为函数定义的。
③函数没有返回值时(void),可以省略,也可写成“return;”
④整型返回值在定义时可以省去说明。
11.2.1 main函数的参数
完整的main函数原型如下:
int main(int argc, char *argv[])
int main(int argc, char **argv)
其中,argc是传给main函数的参数的个数,argv指向具体的参数。
使用时在运行时输入,如: linux@ubuntu:~/book$./test 192.168.1.12 5555 8888 //test3个都是传入的参数
11.3 函数的声明
帮助编译器进行对照检查,函数的声明写在main函数之前;
11.4 函数与数组
当形参是数组形式时,其本质上也是一个指针。数组作为实参传递时,形参并没有复制实参所有的内容,而是复制了实参数组的首地址。
13. 算法
13.1 冒泡排序
排序过程如下:
①比较第一个数和第二个数,交换使最大的数在后;然后比较第二个和第三个数,以此类推,直到第n-1和第n个数比较为止,完成了第一趟冒泡排序,最终最大的数在最后一个元素位置上。
②对前n-1个数进行第二趟冒泡排序。
③重复上述过程,共经过n-1趟冒泡排序后,数据从小到大排序结束。
13.2 选择排序
排序过程如下:
①通过n-1次比较,从n个数中找出最小的,与第一个数交换,完成了第一次选择排序,最终最小的数在首位。
②再通过n-2次比较,从剩余的n-1个数中选出次小的,和第二个数交换
③重复上述过程,共经过n-1次选择排序后,数据从小到大排序结束。
14. hello world
14.1 分析建模
输出字符串 “hello world”
14.2 画流程图
开始--->输出字符串--->结束
14.3 翻译C语言
注释:写给程序员自己看
// 单行注释(作者 时间)
/*
多行注释(程序说明)
*/
# define _CRT_SECURE_NO_WARNINGS //新版VS中使用scanf_s代替scanf,更规范,此定义取消此报错
# include <stdio.h> //printf()函数的头文件
int main(viod)
{
printf("hello world!\n");
/*
函数名(参数名1,参数名2,)
\n 换行转义字符
*/
return 0;
}
14.4 运行调试
单步调试(F5)需要先设置断点(在行号前点击)
//几个示例:
printf右结合,从右到左计算
首先:a++,第四位输出定格在2,a=3,
其次,a,第三位输出不能确定a=3
然后:++a,此时a=4,但第二位还不能确定
最后:第一个赋值确定为4,a=5,第二位第三位为5可以确定
总结:先赋值的第一次就可以确定,后赋值的要等运算完成,才能确定。
首先,++a等于7第一个
其次,第二个++a,影响到了前面的值,第二个等于8,所以第一个也为8
最后,后面的自加运算不受影响。
总结:只有第一个受到了第二个的影响。