C语言学习笔记

第一章 C语言概述

程序语言概述

程序语言的发展历程可分为以下:

  1. 机器语言

低级语言,也称为是二进制代码语言。计算机是由0和1组成的二进制数组成一串指令来表达计算机操作的语言。机器语言他的特点就是计算机可以直接识别,不需要进行任何“翻译”。

  1. 汇编语言

汇编语言是面向机器的程序设计语言。为了减轻使用机器语言编程的痛苦,所以用英文字母或符号来替代机器语言的二进制码,这样就把不易理解的机器语言转变为汇编语言。

  1. 高级语言

为了使程序语言更加贴近人类的自然语言,同时又不依赖于计算机硬件,于是产生了人们易于理解的高级语言。

例如:C/C++、Java、Python、Golang(Go)等

C语言的历史

C语言是在BCPL(B语言)的基础上发展和完善起来的,而B语言是由UNIX的研制者丹尼斯·里奇和肯·汤普逊于1970年研制出来的。

C用语言是面向过程的高级编程语言。

  1. C语言的特点
  • 高效性:它继承了低级语言的优点,产生了高效的代码,并具有友好的可读性和编写性。

  • 灵活性:C语言的语法不拘一格,可在原有语法基础上进行创造、复合,从而给程序员更多想象空间。

  • 功能丰富:C语言除了所具有的类型之外,还可以使用丰富的运算符和自定义的结构类型来表达任何复杂的数据类型,完成所需要的功能。

  • 移植性好:C语言在不同的操作系统夏,只需要简单地修改或者不用修改即可进行跨平台开发的程序开发操作。

  1. 一个简单的C语言程序
#include<stdio.h>
int main(){
	printf("Hello World");
	return 0;
}
    
/*
1. #include<stdio.h>:这个语句功能是进行有关的预处理操作。
   include称为文件包含命令,后面的尖括号中的内容称为头部文件或首文件。
2. 空行:在C语言中空格和空行不会影响C程序的编译。
3. int main() 函数声明:这个代码的意思是声明main函数为一个返回值,是整型的函数。
   程序都是从main函数开始执行的,然后进入main函数中,执行main函数中的内容。
4. 函数体:两个大括号构成函数体,函数体也可以被称为是函数的语句块
5. 执行语句:执行语句就是函数体中要执行的动作内容。每个执行语句都以”;“分号结尾。
*/

第二章 算法

算法的优劣

​ 衡量一个算法的好坏,通常要从以下几个方面来分析:

​ (1) 正确性:所写的算法应能满足具体问题的要求,即对任何合法的输入,算法都能给出正确的结果。

​ (2) 可读性:算法被写好之后,该算法被理解的难易程度。

​ (3) 健壮性:指当输入的数据非法时,算法也会做出相应判断,而不会因为输入的错误造成瘫痪。

​ (4) 时间复杂度和空间复杂度:时间复杂度就是算法运行所需要的时间。空间复杂度是指算法运行所需存储空间的多少。

算法描述

自然语言:用人们通俗易懂的语言来描述算法

  1. 求N!( 阶乘 ) :

​ 1) 定义三个变量i、n及mul,为i和mul均赋初值为1。

​ 2) 从键盘中输入一个数,赋给n。

​ 3) 将mul乘以i的结果赋给mul。

​ 4) i的值加1,判断i的值是否大于n,如果大于n,则执行步骤(5),否则执行步骤(3)。

  1. 将mul的结果输出。

  2. 任意输入三个数,求这三个数中的最小数:

​ 1) 定义4个变量,分别为x、y、z以及min。

​ 2) 输入大小不同的3个数,分别赋给x、y、z。

​ 3) 判断x是否小于y,如果小于,则将x的值赋给min,否则将y的值赋给min。

​ 4) 判断min是否小于z,如果小于,则执行步骤(5),否则将z的值赋给min。


第三章 数据类型

关键字

C语言中有32个关键字。

关键字是不允许作为标识符出现在程序中的。

autobreakcontinueconstcase
defaultelseifwhiledo
charenumfloatdoubleint
fordatacodestructreturn
longbitshortswitchunsingned
voidstaticgotosizeoftypedef

标识符

在C语言中为了在程序的运行过程中可以使用变量、常量、函数、数组等,就要为了这些形式设定一个名称,而设定的名称就是所谓的标识符。

1)设定标识符时由字母、下划线、数组组成,除开头外,在其他位置均可。

2)所有的标识符必须由字母或下划线开头,而不能以数字或者符号开头。

3)C语言是区分大小写,英文字母的大小写是代表不同意思的。

4)标识符不能是关键字。

5)标识符的命名最好具有相关的含义。

数据类型

程序在运行时要做的内容就是处理数据。程序要解决复杂的问题,就要处理不同的数据。

不同的数据都是以自己本身的一种特定形式存在的(如整型字符型、实型),不同的数据类型占用不同的存储空间。

  1. 基本类型

​ 基本类型是C语言中的基础类型,其中包括整型、字符型、浮点型、枚举类型。

  1. 构造类型

​ 指使用基本类型的数据,或者使用已经构造好的数据类型,进行添加、设计,构造出新的数据类型,使新构造的类型能满足解决问题所需的数据类型。构造类型包括数组类型、结构体类型和共用体类型等。

  1. 指针类型

​ 指针是C语言的精华,指针的值表示某个内存地址。

  1. 空类型

​ 空类型的关键字是void,其主要作用是对函数返回的限定和对函数参数的限定。

常量

常量是指程序运行过程中无法改变的量。具有数值型常量、字符型常量、符号常量。

(1) 整型常量:直接使用的整形常数。

  1. 八进制整数:在常数前加上0进行修饰即为八进制数,0123。
  2. 十进制整数:不需要再其前面添加前缀的,123。
  3. 十六进制整数:常量前面使用0x作为前缀,表示该常量是用十六进制进行表示的。十六进制中包含数字09以及字母AF。

(2) 实型常量:实型也称为是浮点型,由整数和小数部分组成,并用十进制的小数点进行分隔。表示方式有科学计数方式和指数方式。

  1. 科学计数:使用十进制的小数方法描述实型。123.45
  2. 指数方式:12.3e10

(3) 字符型常量:字符常量和字符串常量两种。

  1. 字符常量:使用单直撇括起一个字符,这种形式就是字符常量。‘a’

​ 字符常量只能包括一个字符,不能是字符串。字符常量是区分大小写的。

  1. 字符串常量:用一组双引号括起的字符序列。“hello”

​ 如果字符串中一个字符都没有,将其称为"空串",此时字符串的长度为0。

​ 在存储字符串时,系统会自动在字符串的末尾添加一个’\0’,作为字符串结尾的标志。

(4) 转义字符:以反斜杠”\“开头,后面跟一个字符或几个字符。

(5) 符号常量:使用一个符号代替固定的常量值,这里使用的符号名就称之为符号常量。

变量

程序运行期间可以改变的量。

(1) 整型变量:是用来存储整型数值的变量。

类别特点
int其值是基本整型常数,在内存中占4个字节,取值范围为-214748367748 ~ 2147483647
Unsigned int其中的int在编写中可以省略,在内存中占4个字节。取值范围为0 ~ 4294967295
short占2个字节,取值范围为-32768 ~ 32767
Unsigned short占2个字节,取值范围为0~65535
long占4个字节,取值范围为-2147483648 ~ 2147483647
Unsigned long占4个字节,取值范围为0 ~ 3294967295

(2) 实型变量:是用来存储实型数值的变量。

类别特点
float占4个字节,取值范围为-3.4×1038 ~ 3.4×1038
double在内存中占8个字节,取值范围为-1.7×10-308~1.7×10308
long double在内存中占8个字节,取值范围为-1.7×10-308~1.7×10308

(3) 字符型变量:

​ 字符型变量是用来存储字符常量的变量,在内存中占一个字节,取值范围为-128~127。

​ 定义字符型变量的方法就是用关键字char。

变量的存储类别

C程序中可以选择变量不同存储形式,其存储类别分为静态存储和动态存储。

可以通过存储类修饰符来告诉编译器要处理什么样的类型变量,具体主要有自动(auto)、静态(static)、寄存器(register)和外部(extern)4种。

根据变量的产生时间,可将其分为静态存储和动态存储。

静态存储是指程序运行时为其分配固定的存储空间,动态存储则是在程序运行期间根据需要动态地分配存储空间。

类别作用
auto用于定义一个局部变量为自动的,这意味着每次执行到定义该变量时都会产生新的变量,并且对其重新初始化
static在语句块执行期间,static变量将始终保持它的值,并且初始化操作只在第一次执行时起作用,在随后的运行过程中,变量将保持语句块上一次执行时后.
register通过register变量,程序员可以把某个局部变量指定存放在计算机的某个硬件寄存器中而不是内存.这样做的好处就是可以提高程序的运行速度,但用户无法获取寄存器变量的地址
extern声明了程序中将要用到但尚未定义的外部变量

混合运算

​ 不同的数据类型之间可以进行混合运算,但要转换为同一类型。

​ 例如:将int与char、float进行相加,最后结果存放在double中。


第四章 运算符与表达式

表达式

​ 由操作符和操作数组成。例如 : int num = 1;

​ 表达式本身什么事情也不用做,只是返回结果值,其隐含的数据类型取决于组成表达式的变量和常量的类型。

赋值运算符 和 赋值表达式

“=” 就是赋值运算符,起作用就是将一个数据赋给一个变量。

(1) 变量赋初值

​ 在声明变量时可以为其赋一个初值,就是将一个常数或者一个表达式的结果赋值给一个变量,变量中保存的内容就是这个常量或者赋值语句中表达式的值。

  1. 将常数赋值给变量:类型 变量名 = 常数;
  2. 通过赋值表达式为变量赋初值: 类型 变量名 = 表达式;

​ 产生值的表达式称为右值,因为它出现的位置在表达式的右侧。得到赋值的变量称为左值,因为它出现的位置在左边。并不是所有的表达式都可以作为左值,常量只可以作为右值。

(2) 自动类型转换

​ 在C语言中存在自动类型转换规则。如果把比较短的数值类型变量的值赋给比较长的数值类型变量,那么比较短的数值类型变量中的值会审计为比较长的数值类型,数据信息不会丢失。但是,如果把较长的数值类型变量的值赋给比较短的数值类型变量,那么数据就会减低级别显示,当数据大小超过比较短的数值类型的可表示范围时,会发生数据截断。

(3) 强制类型转换:**(类型名)(表达式),(double) sum **

算术运算 和 算术表达式

(1) 算数运算符:两个单目运算符(正和负)和五个双目运算符(= - * / %)等,单目运算符优先级最高。

(2) 优先级和结核性

  1. 算术运算符的优先级:先乘除、%后加减。
  2. 算数运算符的结合性:优先级相同时,结合方向为“自左向右”。

(3) 自增/自减运算符:++和–,分别是增加1和减少1。

(4) 关系运算符和关系表达式

(5) 关系运算符:用于对两个表达式的值进行比较,返回一个真值1或假值0。

​ 大于、>= 大于等于、< 小于、<= 小于等于、== 等于、!= 不等于

(6) 优先级和结合性:关系运算符的结合性都是自左向右。

逻辑运算符 和 逻辑表达式

​ " 表达式 逻辑运算符 表达式 "

​ 逻辑运算符根据表达式的真或假属性返回真值或假值。表达式的值非零为真。

&& 逻辑与两边真几位真
|| 逻辑或一边真即为真
! 单目逻辑非意为 -> not

逗号运算符 与 逗号表达式

​ 在C语言中,可以用逗号将多个表达式分隔开来。其中,用逗号分隔的表达式被分别计算,并且整个表达式的值是最后一个表达式的值。即:表达式1,表达式2,….,表达式n


第五章 数据输入\输出

字符 数据输入/输出

类别特点
putchar向显示设备输出一个字符, 例如: putchar(‘\101’);
getchar从终端输入一个字符

大写字符和小写字符的ASCII码值相差32。

字符串 数据输入/输出

类别特点
puts输出一个字符串到屏幕上, 例如: puts(" Hello ");
gets将读取的字符串保存在形式参数变量上

格式 输出/输入

(1) printf 函数:向终端输出若干任意类型的数据。

 **printf("格式控制,输出列表");**
  1. 格式控制:用双引号括起来的字符串,其中包括格式字符和普通字符。
  2. 输出列表:列出要进行输出的一些数据,可以是变量或表达式。

​ %d:以十进制数形式输出。

​ %f:以小数形式输出。

​ %c:以字符形式输出,只输出一个字符。

​ %s:输出字符串。

(2) scanf 函数:向终端输入若干任意类型的数据。


第六章

if 语句

在if语句中,首先要判断表达式的值,然后根据该 值的情况控制程序流程。表达式的值不为0,即为真,否则为假。

If语句形式if(表达式) 语句
If…else 语句形式If(表达式) 语句1; Else(表达式) 语句2;
Else…if 语句形式If(表达式) 语句1; Else if(表达式) 语句2; Else 语句;
if(Num==1){  
 Printf("Num == 1");  
}    

/*
这句代码的含义是:
判断变量Num==1的表达式,如果条件成立,那么判断的结果是真值,
则执行下面语句;否则为假值,不执行下面的语句。 
*/

if 的嵌套形式

if( true ){
	if( true ){
		语句
	}else{
		语句
	}
}else{
	语句
}
// 在项目实践中建议不要过多的if else,可参考卫语句。

条件运算符

在使用if语句时,可以通过判断表达式为"真"或"假",从而执行相应的表达式。

if(a>b){  
    Max = a;  
}else{  
    Max = b;  
}  
// --> 可简化为:  max =  (a>b)?a:b  

switch 语句

C语言中可以使用switch语句直接处理多分支选择的情况。

switch( true ){
	case 情况1:
            语句1; 
            break;
	case 情况n:
            语句n;
            break;
	default:
		默认情况语句;
}

第七章 循环控制

while 语句

while( true ){
    printf("hello");
}
/*
	while循环过程:
	while语句首先检验以下条件,也就是括号中的表达式。
	当条件为真时,就执行紧跟其后的语句。每执行一遍循环,程序都将回到while语句处,重新检验条件是否满足。
	如果一开始条件就不满足的花则跳过循环体中的语句,直接执行后面的程序代码。
	如果第一次检验时条件满足,那么第一次或之后的循环过程中,必须得有使条件为假的操作,否则循环将无法终止。
*/

do…while 语句

do{
    printf("hello");
}while( true );
/*
	Do..while语句不管条件是否成立,都会执行一次循环。
	首先执行一次循环体语句的内容,然后判断表达式,当表达式的值为真时,返回重新执行循环体语句。
	执行循环,直到表达式的判断为假为止,此时循环结束。
*/

for 语句

for(表达式1;表达式2;表达式3){
    printf("hello");
}

int sum = 0;
for(int i = 1; i <= 10; i++){
    sum += i;
}
printf("sum = %d" + sum);

/*
	for循环过程:
	当执行for语句时,程序首先计算第一个表达式的值,接着计算第二个表达式的值。
	如果第二个表达式的值为真,程序就执行循环体的内容,并计算第三个表达式;
	然后检验第二个表达式,执行循环;如此反复,直到第二个表达式为假,退出循环。
*/

/*
    for语句表达式1:作用是对循环变量设置处置。
    for语句表达式2:作用是给for循环设定循环条件。
    for语句表达式3:可省略,但此时应另外设法保证循环能正常结束,否则循环将无限制的循环下去。
*/

循环嵌套

一个循环体内又包含另一个完整的循环结构

类别结构
while结构中嵌套while结构while(表达式){ 语句; while(表达式){ 语句; } }
Do…while结构中嵌套do…while结构do{ 语句; do{ 语句; }while(表达式); }while(表达式);
for结构中嵌套for结构for(表达式1;表达式2;表达式3){ 语句; For(表达式1;表达式2;表达式3){ 语句; } }
Do…while结构嵌套while结构do{ 语句; while(表达式){ 语句 } }while(表达式);
Do…while结构嵌套for结构do{ 语句; For表达式1;表达式2;表达式3){ 语句; } }while(表达式);

转移语句

类别特点
goto无条件转移语句,可以使程序立即跳转到函数内部的任意一条可执行语句
break不管表达式的结果如何,都强行终止循环。即break语句是终止并跳出循环,继续执行后面的代码
continue程序回到循环头部继续执行,不退出循环。即作用是结束对本次的循环,跳过循环体中尚未执行的部分,直接执行下一次的循环操作

第八章 数组

一维数组

存储一维数列中数据的集合

一维数组的定义和引用

  1. 定义:类型说明符 数组标识符[常量表达式];

​ 1) 类型说明符是表示数组中所有元素的类型。

			2) 数组标识符表示该数组型变量的名称,命名规则和变量名一致。

​ 3) 常量表达式定义了数组中存放的数据元素的个数,即数组长度。

  1. 引用:数组标识符[下标];

​ 数组的下标从0开始。

一维数组初始化

类别结构
在定义时直接对数组元素赋初值int array[6] = {1,2,3,4,5,6};
只给一部分元素赋值,未赋值的部分元素值为0int array[6] = {1,2,3};
在对全部数组元素赋初值时可以不指定数组长度int array[] = {1,2,3,4};

二维数组

二维数组的定义和引用

  1. 定义:数据类型 数组名[常量表达式1][常量表达式2];

​ 其中"常量表达式1"被称作行下标,"常量表达式2"被称作列下标。

  1. 引用:**数组名 [行] [列] **

​ 行下标的取值范围为0n-1,列下标的取值范围为0m-1。

二维数组初始化

类别结构
可以将所有数据卸载一个大括号内,按照数组元素排列顺序对元素赋值int array[2] [2] = {1,2,3,4};
在为所有元素赋值时,可以省略行下标,但是不能省略列下标int array[] [2] = {1,2,3,4};
也可以分行给数组元素赋值
二维数组也可以直接对数组元素赋值int A2[2] [3]; A2[0] [0] = 1;

字符数组

字符数组的定义和引用

  1. 定义:char 数组标识符[常量表达式];

    ​ char cArray[5];

  2. 引用:数组名[下标]

字符数组初始化

  1. 逐个字符赋给数组中的各元素:char cArray[5] = {‘a’,‘b’,‘c’,‘d’,‘e’};
  2. 在定义字符数组时进行初始化,此时可以省略数组长度

​ Char cArray[] = {‘H’,‘E’};

  1. 利用字符串给字符数组赋初值

​ Char cArray[] = {“Hello”} 或者将{}去掉 char cArray[] = “Hello”

字符数组输入和输出

  1. 使用格式符"%c":实现字符数组中字符的逐个输入和输出。
  2. 使用格式符"%s":实现字符数组中字符的全部输入和输出。

多维数组

​ 数据类型 数组名[常量表达式1] [常量表达式2]…[常量表达式n];

数组的排序算法

选择法排序

每次选择所要排序的数组中的最大值(由大到小排序选择最大值,由小到大排序选择最小值)的数组元素,将这个数组元素的值与最前面没有排序的数组元素的值互换。

代码思路

(1)声明一个整型数组,并通过键盘为数组元素赋值。

(2)设置一个嵌套循环,第一层循环为前9个数组元素,并在每次循环时将对应当前次数的数组元素设置为最小值(如果当前是第3次循环,那么将数组中第3个元素(也就是下标为2的元素)设置为当前的最小值);在第二层循环中每循环比较该元素之后的各个数组元素,并将每次比较结果中较小的数设置为最小值,在第二层循环结束时,将最小值与开始时设置为最小值的数组元素进行互换。当所有循环都完成之后,就将数组元素按照从小到大的顺序重新排序了。

冒泡法排序

在排序时,每次比较数组中相邻的两个数组元素的值,将较小的数(从小到大排序)排在较大的数前面。

代码思路

(1)声明一个整型数组,并通过键盘为数组赋值。

(2)设置一个嵌套循环,第一层为后9个数组元素。在第二层循环中,从最后一个数组元素开始向前循环,直到前面第一个没有进行排序的数组元素。循环比较这些数组元素,如果在比较中后一个数组元素的值小于前一个数组元素的值,则将两个数组元素的值进行互换。当所有循环都完成以后,就将数组元素按照从小到大的顺序重新排序了。

交换法排序

将每一位数与其后的所有数一一比较,如果发现符合条件的数据,则交换数据。

首先,用第一个数依次与其后的所有数进行比较,若谷哦存在比其值大(小)的数,则交换这两个数,继续向后比较其他数直至最后一个数。然后再使用第二个数与其后面的数进行比较,如果存在比其他值大(小)的数,则交换这两个数。继续向后比较其他数,直至最后一个数完成。

代码思路

(1)声明一个整型数组,并通过键盘为数组赋值。

(2)设置一个嵌套循环,第一层循环为前9个数组元素,然后在第二层循环中,使用第一个数组元素分别与后面的数组元素依次进行比较,如果后面的数组元素值小于当前数组元素值,则交换两个元素值,然后使用交换后的第一个数组元素继续与后面的数组元素进行比较,直到本次循环结束。将最小的数组元素值交换到第一个数组元素的位置,然后从第二个数组元素开始,继续与后面的数组元素进行比较。以此类推,直到循环结束,就将数组元素按照从小到大的顺序重新排序了。

插入法排序

其原理是抽出一个数据,在前面的数据中寻找相应的位置插入,然后继续下一个数据,直到完成排序。

代码思路

(1)声明一个整型数组,并通过键盘为数组赋值。

(2)设置一个嵌套循环,第一层循环为后9个数组元素,将第二个元素赋给中间变量,并记录钱一个数组元素的下标位置。在第二层循环中,首先要判断是否符合循环的条件,允许循环的条件是记录的下标位置必须大于等于第一个数组元素的下标位置,并且中间变量的值小于之前设置下标位置二点数组元素,如果满足循环条件,则将设置下标位置的数组元素值赋给当前的数组元素,然后将记录的数组元素下标位置向前移动一位,继续进行循环判断。内层循环结束之后,将中间变量中保存的数值赋值给当前记录的下标位置之后的数组元素,继续进行外层循环,将数组中下一个数组元素赋值给中间变量,再通过内层循环进行排序,依次类推,直到循环结束,就将数组元素按照从小到大的顺序重新排序了。

折半法排序

又称快速排序,是选择一个中间值middle(在程序中使用数组中间值),然后把比中间值小的数据放在左边,比中间值大恶数据放在右边(具体的实现是从两边找,找到一对后进行交换),后对两边分别递归使用这个过程。

代码思路

(1)声明一个整型数组,并通过键盘为数组赋值。

(2)定义一个函数,用于对数组元素进行排序,函数的3个参数分别表示递归调用时数组最开始的元素、最后元素的下标位置以及要排序的数组。声明两个整型变量,作为控制排序算法循环的条件,分别将两个参数赋值给变量i和j,i表示左侧下标,j表示右侧下标。首先使用do…while语句来设计外层循环,条件为i小于j,表示如果两边的下标交错就停止循环,内层的两个循环分别用来比较中间值两侧的数组元素,当左侧的数值小于中间值时,取下一个元素与中间值进行比较,否则退出第一个内层循环;当右侧数值大于中间值时,取前一个元素与中间值进行比较,否则退出第二个内层循环。然后判断i的值是否小于等于j,如果时,则交换以i和j为下标的两个元素值,继续进行外层循环。当外层循环结束以后,以数组第一个元素到以j为下标的元素为参数递归调用该函数,同时,以i为下标的数组元素到数组最后一个参数也作为参数递归调用该函数。以此类推,直到将数组元素按照从小到大的顺序重新排列为止。

排序算法的比较

  1. 选择排序:在排序过程中共需要进行n(n-1)/2次比较,互相交换n-1次。适用于数量较小的排序。
  2. 冒泡排序:最好的情况是正序,只要比较一次即可。最坏的情况是逆序,需要比较n2次。
  3. 交换排序:与冒泡排序类似,正序时最快,逆序时最慢,排序有序数据时效果最好。
  4. 插入排序:需经过n-1次插入过程,如果数据恰好一个插入序列的最后端,则不需要移动数据,可节省时间,因此,若原始数据基本有序,此算法具有较快的运算速度。

字符串处理函数

字符串复制

用于复制特定长度的字符串到另一个字符串中

​ strcpy (目的字符数组名,源字符数组名)

​ 功能:把源字符数组名中的字符串复制到目的字符数组中,字符串标志"\0"也一同复制。

字符串连接

将一个字符串连接到另一个字符串的末尾

​ strcat(目的字符数组名,源字符数组名)

​ 功能:把源字符数组中的字符串连接到目的字符数组中字符的后面,并删去目的字符串数组又的串结束标志"\0"。

字符串比较

​ Strcmp(字符数组名1,字符数组名2)

​ 功能:按照ASCII码顺序比较两个数组中的字符串,并返回结果。

​ 字符串1 = 字符串2,返回值为0;

​ 字符串1 > 字符串2,返回值为正数;

​ 字符串1 < 字符串2,返回值为负值。

获取字符串长度

​ strlen(字符数组名);

​ 功能:计算字符串的实际长度(不含字符串结束标志"\0"),函数返回值为字符串的实际长度。


第九章 函数

构成C程序的基本单元数以函数。

编写程序时,并不是将所有内容都放在主函数main中。为了方便规划、组织、编写和调试,一般的做法是将一个程序划分成若干个程序模块,每一个程序模块都完成一部分功能。

函数的定义

  1. 函数头,分为3个部分:int Add (int num1, int num2)

​ 1)返回值类型。可以是某个C数据类型。

​ 2)函数名。即函数的标识符,函数名在程序中必须是唯一的。

​ 3)参数表。参数表可以没有变量也可以有多个变量。

  1. 函数体

函数体包括局部变量的声明和函数的可执行代码。

int main(){  // 所有的C程序都必须有一个main函数return 0;
}

1)无参函数

​ 返回值类型 函数名(){

​ 函数体…

​ }

2)空函数

​ 类型说明符 函数名(){ }

返回语句

​ 有两个主要用途:

​ 1)利用返回语句能立即从所在的函数中退出,即返回到调用的程序中去。

​ 2)利用语句能返回值,即将函数值赋给调用的表达式中。

​ 返回类型为void的函数就没有返回值。

​ 返回值:用户在调用某个函数时,通常是希望能得到一个确定的值。

函数参数

作用是传递数据给函数使用,函数利用接收到的数据进行具体的操作处理。

形式参数 与 实际参数

  1. 通过名称理解

​ 形式参数:即形式上存在的参数。

​ 实际参数:即实际存在的参数。

  1. 通过作用理解

​ 1) 形式参数:在定义函数时,函数名后面括号的变量名称为"形式参数"。在函数调用之前,传递给函数的值将被复制到这些形式参数中。

  1. 实际参数:在调用一个函数时,也就是真正使用一个函数时,函数名后面括号中的参数为"实际参数"。

    ​ 函数的调用者提供给函数的参数叫实际参数。

    ​ 实际参数是表达式计算的结果,并且被复制给函数的形式参数。

  2. 通过一个比喻来形容形式参数和实际参数

​ ”母亲拿来了一袋牛奶,将牛奶倒入一个空奶瓶中,然后喂宝宝喝牛奶。函数的作用就相当于宝宝用奶瓶喝牛奶这个动作,实参就相当于母亲拿来的一袋牛奶,而空的奶瓶就相当于形参。牛奶放入奶瓶这个动作相当于将实参传递给形参,使用灌好牛奶的奶瓶就相当于函数使用参数进行操作的过程。

数组作为函数参数

当数组作为函数的实参时,只传递数组的地址,而不是将整个数组赋值到函数中。当用数组名作为实参调用函数时,只想该数组的第一个元素的指针就被传递到函数中。

类别特点
数组元素作为函数参数由于实参可以是表达式形式,数组与那苏可以是表达式的组成部分,因此数组元素可以作为函数的实参,与用变量作为函数实参一样,是单向传递。
数组名作为函数参数数组名作为函数参数时,实参和形参都应使用数组名。
使用指针作为函数参数将函数参数声明为一个指针。当数组作为函数的实参时,只传递数组的地址,而不是i将整个数组赋值到函数中去。当用数组名作为实参调用函数时,指向该数组的第一个元素的指针就会被传递到函数中。

函数的调用

  1. 函数语句调用:函数名();
  2. 函数表达式调用:iNum = iNum3*函数名();
  3. 函数参数调用:iNum = 函数名(函数参数n);

嵌套调用

在其函数体内包含另一个函数的定义。

递归调用

函数可以直接或间接地调用自己

内部函数 和 外部函数

内部函数

即只被这个函数所在地源文件使用。

语法: static 返回值类型 函数名(参数列表)

外部函数

可以被其他源文件调用的函数

语法: extern 返回值类型 函数名(参数列表)

局部变量 和 外部变量

局部变量

在一个函数的内部定义的变量即为局部变量,作用域仅限于函数内部的所有语句块

全局变量

可以在程序的任何位置进行访问的变量。主要作用时增加函数间数据联系的渠道


第十章 指针

指针相关概念

地址 与 指针

什么是地址?地址就是内存区中对每个字节的编号。

在程序中定义了一个变量,在进行编译时就会给该变量在内存中分配一个地址,通过访问这个地址可以找到所需的变量,这个变量的地址就称为该变量的"指针"。

变量 与 指针

变量的地址是变量和指针二者之间连接的纽带,如果一个变量包含了另外一个变量的地址,则可以理解成第一个变量指向第二个变量。所谓"指向"就是通过地址来体现的。

指针变量

一个变量的地址称为该变量的指针。如果有一个变量专门用来存放另一个变量的地址,它就是指针变量。

  1. 指针变量的一般形式:类型说明符 * 变量名
  2. 指针变量的赋值:&变量名;
// C语言中提供了地址运算符"&"来表示变量的地址。
int a;
int *p;
p = &a;
  1. *指针变量的引用:指针变量,其含义是引用指针变量所指向的值

数组与指针

一维数组与指针

当定义一个一维数组时,系统会在内存中为该数组分配一个存储空间,其数组的名称就是数组在内存中的首地址。若在定义一个指针变量,并将数组的首地址传给指针变量,则该指针就指向了这个一维数组。

int *p;
int a[10];
p = a;

二维数组与指针

​ 定义一个3行5列的二维数组

​ 1)&a[0][0]既可以看作数组0行0列的首地址,也可以看作二维数组的首地址。&a[m][n]就是第m行n列元素的地址。

​ 2)a[0]+n表示第0行第n个元素的地址。

​ 3)&a[0]是低0行的首地址,当然&a[n]就是第n行的首地址。

​ 4)a+n表示第n行的首地址。

​ 5)((a+n)+m)表示第n行第m列元素。

​ 6)*(a[n]+m)表示第n行第m列元素。

​ *(a+i)和a[i]是等价的。

字符串与指针

可以通过两种方式访问一个字符串:

第一种方式就是使用字符数组来存放,从而实现对字符串的操作;

第二种就是使用字符指针来指向一个字符串,此时可不定义数组。

char *string = "hello";
printf("%s",string);

字符串数组

// 字符数组是一个一维数组,而字符串数组是以字符串作为数组元素的数组,可以将其看作一个二维字符数组。
char county[5][20] = {
	"China",
	"Russia",
	"Japan",
	"Germany",
	"Switzerland"
}

指向指针的指针

一个指针变量可以指向整型变量、实型变量、字符类型变量,也可以指向指针类型变量。

当这种指针变量用于指向指针类型变量时,则称之为指向指针的指针变量。

定义:类型标识符 **指针变量名;

即 int **p。


第十一章 结构体

结构体的概念

结构体是一种构造类型,它是由若干成员组成的。其成员可以是一个基本数据类型,也可以是一个构造类型。既然结构体是一种新的类型,就需要先对其进行构造,这里称这种操作为声明一个结构体。

​ 声明结构体时使用的关键字时struct,其一般形式如下:

struct 结构成员名{

成员列表;

}

结构体变量的定义

(1)先声明结构体类型,再定于变量。

​ 定义结构体变量后,系统会为其分配内存单元(结构体内存总和为各成员内存之和)

(2)在声明结构类型时,同时定义变量。

/*
struct 结构体名{
    成员列表;
}变量名列表;  
*/

struct Student{  
    char cName[10];  
    char cShape[20];  
    int iPrice;  
}product1,product2;  

结构体变量的引用

​ 定义结构体类型变量后,不能直接将一个结构体变量作为一个整体进行输入和输出。

​ 要对结构体变量进行赋值、存取或运算,实际上就是对结构体成员进行操作。即:结构体变量名 . 成员名

结构体的初始化

/*
struct 结构体名{
    成员列表;
}数组名 = {
    初始值列表
}
*/

struct Student{
    char cName[20];
    char cSex;
    int iGrade;
}sutudent1 =  {"HanXue","W",3};

结构体数组

/*
struct 结构体名{
    成员列表;
}数组名;
*/
     
struct Student{
    char cName[20];
    char cSex;
    int iGrade;
}sutudent1[5];  

第十二章 文件

文件概述

"文件"是指一组相关数据的有序集合。这个数据集有一个名称,叫作文件名。

所有文件都可以通过流进行输入、输出操作。

​ 分为文本文件和二进制文件两大类。

  1. 文本文件,也称为ASCII码。这种文件再保存时,每个字符对应一个字节,用于存放对应的ASCII码。
  2. 二进制文件,不是保存ASCII码,而是按二进制的编码方式来保存文件内容。

文件基本操作

包括文件的打开和关闭。

​ 除了标准的输入和输出文件外,其他所有的文件都必须先打开在使用,使用后还必须关闭该文件。

文件指针

文件指针是一个直线文件有关信息的指针,这些信息包括文件名、状态和当前位置,它们保存再一个结构体变量种。

在使用文件时需要在内存中为其分配空间,用来存放文件的基本信息。C语言规定的文件类型为FILE型。

// 文件声明
typedef struct{
	short level;
	unsigned flags;
	char fd;
}FILE;

// 从上面的结构可以发现,使用typedef定义了一个FILE为该结构体类型。
// 在编写程序时可直接使用上面定义的FILE类型来定义变量,在定义变量时不必将结构体内容全部给出,只需写成:**FILE \*fp**;

文件的打开

fopen函数用来打开一个文件,打开文件的操作就是创建一个流。

/*
	 File *fp;  
	 fp = fopen(文件名,使用文件方式);
*/

FILE *fp;  
fp = ("123.txt","r");

文件的读写

fputc 函数

作用是把一个字符写到磁盘文件(fp所指向的是文件)中。

​ 形式为:ch = fputc(ch,fp);

​ 其中,ch是要输出的字符,它可以是一个字符常量,也可以是一个字符变量。

​ fp是文件指针变量,如果函数输出成功,则返回值就是输出的字符;如果输出失败,则返回EOF。

fgetc 函数

作用是从指定的文件(fp指向的文件)读入一个字符赋予 ch。

​ 形式为:ch=fgetc(fp);

​ 需要注意的是,该文件必须以读或读写的方式打开。当函数遇到文件结束符时,将返回一个文件结束标志EOF。

fputs函数

作用是向指定的文件写入一个字符串,其中字符串可以时字符串变量,也可以是字符数组名、指针或变量。

​ 形式为:fputs(字符串,文件指针);

​ 与fputc函数相似,区别在于fputc函数每次只向文件中写入一个字符,而fputs函数每次向文件中写入一个字符串。

fgets函数

作用是从指定的文件中读取一个字符串到字符数组中。

​ 形式为:fgets(字符数组名,n,文件指针);

​ n表示所得到的字符串中字符的个数(包括"\0")。

fprintf函数

它的作用是将整型变量i的值以"%d"的格式输出到fp指向的文件中。

​ 形式为:ch=fprintf(文件类型指针,格式字符串,输出列表);

​ 例如:fpintf(fp,“%d”,i)

fscanf函数

​ 形式为:fscanf(文件类型指针,格式字符串,输入列表);

fread 和 fwrite 函数
  1. fread(buffer,size,count,fp)

    作用是从fp所指向的文件中读入count次,每次读size字节,读入的信息存在buffer地址中。

  2. fwrite(buffer,size,count,fp)

    作用是将buffer地址开始的信息输出count次,每次写size字节到fp所指的文件中。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值