C语言程序设计
一、简介
1、简介:C 语言是一种通用的高级语言,最初是由丹尼斯·里奇在贝尔实验室为开发 UNIX 操作系统而设计的。C 语言最开始是于 1972 年在 DEC PDP-11 计算机上被首次实现。C语言也是其它众多高级语言的鼻祖语言,所以说学习C语言是进入编程世界的必修课。
2、特点: 易于学习、结构化语言、它产生高效率的程序、它可以处理底层的活动、它可以在多种计算机平台上编译。
二、环境配置
下载对应的电脑软件:
Windows:dev c++、macOS:Xcode
C程序开发过程(win环境下):
.c文件->.obj文件->.exe文件->程序结果
三、c程序结构
C 程序主要包括以下部分:
预处理器指令、函数、变量、语句 & 表达式、注释
具体结构:
1、#include <stdio.h>就是一条预处理命令, 它的作用是通知C语言编译系统在对C程序进行正式编译之前需做一些预处理工作。
2、函数就是实现代码逻辑的一个小的单元。
3、int main() 是主函数,程序从这里开始执行
4、printf()是输出函数,在屏幕上输出指定信息
5、return 0; 终止 main() 函数,并返回值 0。
四、基础语法
一、分号
在 C 程序中,分号是语句结束符。每个语句必须以分号结束。
注意:一定要记得写分号;
二、注释
//单行注释
/*
多行注释
*/
在写代码培养写注释的习惯
三、标识符
标识符可以是字母(A~Z,a~z)、数字(0~9)、下划线_组成的字符串,并且第一个字符必须是字母或下划线。
注意:
(1)硬性要求
A.不能使用关键字(main等)、保留字(goto)、特殊符号命名(null、true、false)
B.标识符严格区分大小写
C.标识符长度最好不要超过8位
(2)软性要求
a、望文生义
b、类名:每个单词首字母大写,其他单词小写
c、变量名/函数名/方法名:第一个单词首字母小写,其他单词首字母大写,被称为驼峰命名
d、包名:每个单词都小写:com.day1
e、常量:全大写
四、字符数据的输入与输出
1、字符输入函数
<变量>=getchar();
2、字符输出函数
putchar(变量);
#include <stdio.h>
int main()
{
char a;
a=getchar();
putchar(a);
return 0;
}
想换行用putchar(‘\n’)
五、格式化输入与输出
1、格式化输入scanf()
scanf(‘’格式控制’’,地址表列);
eg: scanf(‘’%d‘’&a);
注意:要加&,&是地址符
2、格式化输出printf()
printf();
五、变量
1、概念:是计算机中一块存储空间,是存储数据的基本单元
2、变量的组成部分:数据类型、变量名、数据
语法:数据类型 变量名 =数据;
注意:在定义中不允许连续赋值,如int a=b=c=5;是不合法的。
3、变量的定义:
(1)先声明,再分配空间:
声明:数据类型 变量名;
int a;
赋值:变量名 = 值;
a=3;
(2)声明的同时并赋值:
数据类型 变量名=值;
int b=5;
(3)同时定义多个相同数据类型的变量:
数据类型 变量1,变量2,变量名3=值,变量名;
int c,d,f=9;
常用:
数据类型 | 字节 | 应用 | 示例 |
char | 1 | 用于存储单个字符 | char a=‘a’; |
int | 2 | 用于存储整数 | int a=1; |
float | 4 | 用于存储小数 | float a=1.1 |
double | 8 | 用于存储位数更多的小数 | double pi=3.1415926 |
注意:
1、int、short int、long int在不同编译环境下,所取范围不同
2、ANSI标准定义int是占2个字节,TC是按ANSI标准的,它的int是占2个字节的。但是在VC里,一个int是占4个字节的。
常用:
格式符 | 说明 | 举例 |
%d | 整数 | int a=10; |
%c | 单个字符 | char a=‘a’; |
%s | 字符串 | |
%f/%lf | 小数 | float/double a=3.14 |
六、常量
符号常量:可以用一个标识符来表示一个常量,符号常量在使用之前必须先定义
#include<stdio.h>
//#define 标识符 常量值
#define a 11
int main()
{
printf("a=%d\n",a);
return 0;
}
宏定义: 必须用#define
自动类型转换
char->int->double
1、 不同类型有低向高转化在运算
2、 赋值号右边转化成左边类型
3、 所有浮点运算都转换成双精度运算
4、char、short型参与运算前先转换成int型
强制类型转换
(数据类型) (表达式) eg:(int)(x+y)
注意:
1、强制转换数据类型和表达式都必须加括号
2、转换后不会改变原数据的类型及变量及变量值,只是本次运算临时转换
3、不遵守四舍五入原则
七、运算符
1、算数运算符
+ - * / %(取模)
特殊:
1、++、--(自加、自减运算符:++a、--a先增减再运算,a++、a—先运算,后增减)
注意:
A、除法:如果是整数相除,结果也是整数(反之小数也是一样) eg:3/2=1,5.0/2=2.500000
B、取模:只适合两个整数
2、赋值运算符
= += -= *= /=
3、关系运算符
>:大于
>=:大于等于
<:小于
==:小于等于
!=:不等于
4、逻辑运算符
(1)&&:逻辑与,两端都必须是布尔表达式(结果为boolea的表达式),只有当两端同时为true,只要有端为false,则结果为false
(2)||:逻辑或,两端只要有一端为true,结果就true,两端同时为false,结果才为false
(3)!:逻辑非,在原来的结果基本上取反
5、位运算符
p | q | p&q | p|q | p^q |
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
<<二进制左移运算符
>>二进制右移运算符
原码:
原码就是符号位加上真值的绝对值
[+1]原 = 0000 0001
[-1]原 = 1000 0001
反码:
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
补码:
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
位移码:
将其补码的符号位取反
X=-101011 , [X]原= 10101011 ,[X]反=11010100,[X]补=11010101,[X]移=01010101
6、三目运算符
表达式1 ? 表达式2 : 表达式3; 左正右负
八、分支结构
一、if分支
1.if分支的基本语法
if(条件判断){
//条件成立,执行对应的语句
}
执行的原理:如果if后面()中的条件成立- true,则执行{}中的语句;条件不成立- false,则执行{}后面的内容
2、if...else的基本语法
if(条件判断){
//条件成立,执行对应的语句
}else{
//否则执行的语句
}
执行的机制:如果条件成立,则执行if{}中的内容;否则执行else{}中内容
3、多分支if结构
if(条件判断){
语句1
}else if(条件判断2){
语句2
}else if(条件判断3){
语句3
}else {
语句4
}
执行流程:从上往下一次判断,哪个条件成立,则执行对应{}中的语句
4、嵌套的if结构
if{
if(条件判断){
语句1
}else if(条件判断2){
语句2
}else{
语句
}
}
执行流程:先判断外层的if条件是否成立,成立再判断内层的if条件
二、等值分支结构
1、语法:
switch(表达式){
case 值1:语句;
case值2:语句;
…
default:语句n;
}
2、细节
(1)break:终止、结束switch..case结构,防止case穿透
三、局部变量
1、概念:定义在函数内部的变量
2、特点:
(1) 局部变量必须先赋值再使用
(2) 作用范围:从定义位置开始,到定义它的代码块结束
(3)在重合的作用范围内,不允许命名冲突
九、循环结构
一、理解
1、概念:通过某个条件,重复并且有规律的执行一段代码
2、循环组成部分:循环的初始值、循环的条件、循环变量的改变、循环体
3、循环分类:while循环、do..while循环、for循环
二、while循环
1、语法
while(布尔表达式/判断条件- true/false){
//循环体
//循环变量的改变
}
执行原理:先执行循环变量的初始化,再判断循环条件,条件满足—true,则执行循环体,同时循环变量发生改变,再次的判断循环条件……直到循环条件结果为false,跳出循环
2、细节
(1)循环变量的初始化数据必须给的合理
(2)特点:循环次数0~n次,先判断,再运行
(3)循环的变量改变没有执行,可能会导致出现死循环
(循环无穷尽执行,ctrl/command+c结束)
三、do..while循环
1、语法
do{
//循环体
//循环变量的改变
}while(循环判断条件)
2、细节
(1)执行原理:先执行,再判断,执行的次数为1~n次
(2)注意:不管初始数据给的是否合理,循环体至少执行一次
四、for循环
1、语法
for(循环变量的初始化;判断条件;循环变量的改变){
//循环体
}
2、细节
(1)执行原理:先执行()中的循环变量初始化,再判断循环条件是否成立,true-成立,则执行循环体,再执行循环变量的改变,然后再判断循环条件\…直到循环条件不成立,则跳出循环结构
(2)执行特点:先判断,再执行
得到num的百位、十位、个位
百位:num/100
十位:num%100/10
个位:num%10
五、循环的控制语句
1、break:终止循环结构
流程图
2、continue:中止本次循环,从而进入下一个循环
流程图
六、循环的嵌套
1、概念:在一个循环结构中,定义了另一个完整的循环结构
2、特点:先判断外层循环条件,再执行内层循环
循环的次数=外层循环的循环次数*外层循环的循环次数
七、goto语句
C 语言中的 goto 语句允许把控制无条件转移到同一函数内的被标记的语句。
注意:在任何编程语言都不建议使用goto语句
十、数组
一、理解
1、引言
目前程序存在的问题:一个变量只能存储一个数据,而且没有办法进行统一操作
2、数组
一组连续的存储空间,可以同时存储多个相同类型的数据,并且可以进行统一操作
3、数组的注意点
(1)同类型
(2)确定数组长度
二、数组的定义
1、先声明,再分配空间
(1)声明:确定数据类型
数据类型[] 数组名 ;
int a[];
(2)再分配空间:确定数组的长度
0 | 1 | 2 | 3 | 4 | 下标 |
2、数组的细节
(1)数组的下标从0开始,依次为1,2,3…,最大的下标为数组的长度-1
(2)数组的遍历:
for(i=1;i<数组长度;i++){
//通过 数组名[i];
}
(3) 在声明数组后没有进行初始化的时候,静态(static)和外部(extern)类型的数组元素初始化元素为0,自动(auto)类型的数组的元素初始化值不确定。
(4)元素个数小于数组的长度时,多余的数组元素初始化为0;
三、数组的初始化
(1) 数据类型 数组名称[长度n] = {元素1,元素2…元素n};
(2)数据类型 数组名称[] = {元素1,元素2…元素n};
(3)数据类型 数组名称[长度n]; 数组名称[0] = 元素1; 数组名称[1] = 元素2; 数组名称[n-1] = 元素n;
四、数组的遍历
通过for循环遍历每一个数组
#include <stdio.h>
int main()
{
int a[3]={1,2,3};
for(int i=0;i<3;i++){
printf("%d\n",a[i]);
}
return 0;
}
五、冒泡🫧排序
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
eg:小学排队时按大小个排一样,将一个同学拉出来和后面的比比,如果高就放后面,一直把队伍排好。
由小到大排序
#include <stdio.h>
int main()
{
int a[3]={0,2,1};
int t=0;
for(int i=0;i<2;i++){
if(a[i]>a[i+1]){
t=a[i];
a[i]=a[i+1];
a[i+1]=t;
}
}
for(int j=0;j<3;j++){
printf("%d\n",a[j]);
}
return 0;
}
数组过长可以用代表数组长度:
int len = (int) sizeof(a) / sizeof(*a);
六、字符数组
1、定义
定义:其数组元素的数据类型为字符型变量,关键字为char。
格式:
char 数组名名称[长度] =“字符串值”;
char 字符串名称[长度] = {‘字符1’,‘字符2’,…,‘字符n’,’\0’};
注意:
1、[]中的长度是可以省略不写的;
2、采用第2种方式的时候最后一个元素必须是’\0’,’\0’表示字符串的结束标志;
3、采用第2种方式的时候在数组中不能写中文.在输出字符串的时候要使用:printf(“%s”,字符数组名字);或者puts(字符数组名字);。
2、字符串
a.宇符串是指若干有效字符的序列。C语言中只有字符串常量,没有字符串变量,字符串不是存放在一个变量中,而是存放在一个字符数组里。字符串作为一个整体,它是以“0”作为结束标志的。“0”是指 ASCIl码为0的字符.
b.字符数组的输入和输出
(1)逐个字符输入输出
#include <stdio.h>
int main(void)
{
char a[10];
for (int i=0;i<9;i++) {
scanf("%c",&a[i]); //使用&
}
return 0;
}
(2)整个字符串输入和输出
#include <stdio.h>
int main(void)
{
char a[10];
for (int i=0;i<9;i++) {
printf("%c",a[i]);
}
return 0;
}
c、‘’是字符,’’ ’’是字符串
3、字符串处理函数
a.字符串输出函数 puts
char s[]="Good Morning";
puts(s);
b.字符串输入函数 gets
char a[10];
gets(a);
C.字符串拷贝函数 strcpy(需要引入string.h库)
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20],str2[]="Good Morning";
strcpy(str1,str2);
return 0;
}
使用strepy的数,应注意以下几个问题。
(1)字符数组1 应有足够的长度来容纳复制过来的字符串。
(2)字符数组1必须为字符数组名,字符数组2可以是字符数组名,也可以是字符串常量。
(3)C语言不允许用下列方式将一个字符串常量或字符数组赋给一个字符数组:
char str1 [20], str2 []="Good Morning !"
str1=str2;/* 这种方法是错误的 */
(4)可以只将一个字符串的前面的n个字符拷贝到字符数组中。
例如:
strcpy (strl, str2, 3);
其功能是将字符串 st2 前面的了个字符拷贝到字符数组str1 中。
d.字符串连接函数 strcat
char str1[20]="Good";
char str2[20]="Morning";
strcat(str1, str2);
e.字符串比较函数 strcmp
字符串 1=字符串2,返回值=0;
字符串 1>字符串2,返回值为-正数;
字符串 1<字符串2,返回值为-负数;
f.测试字符串长度函数 strlen
char str1[20]="Good";
printf("%d",strlen(str1));
g.字符串大小写字母相互转换函数 strlwr 和 strupr
格式:
(1)strlwr(字符串)
(2)strupr(字符串)
功能:
(1)将字符串中的大写字母转换成小写字母。
(2)将宇符串中的小写字母转换成大写字母。
七、多维数组
1、二维数组的引用
数组名 [行下标][列下标]
eg:int a[3][4]
0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 |
注意:
a.行下标长度可以省略
b. 二维数组定义的时候,可以不指定行的数量,但是必须指定列的数量
2、二维数组的初始化
格式1:
int a[3][4] = {
{0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};
格式2:
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
十一、函数
一、自定义函数
1、理解
C语言提供了大量的库函数: 比如stdio.h提供输出函数等等,这些具有通用功能的函数是由 C语言开发环境预先提供给我们的,称为标准函数(库函数)。定义新的函数可以减轻main()函数的负担,使程序便于阅读和维护。更重要的是,减少了重复编码的工作量,缩短程序设计周期,提高软件开发和调试效率。
2、函数的定义
〔数据类型说明〕函数名称([参数])
{
执行代码块;
return(表达式);
}
返回值格式:
return 表达式 或者为: return (表达式);
注意:
(1)、[] 包含的内容可以省略,数据类型说明省略,默认是 int 类型函数; 参数省略表示该函数是无参函数,参数不省略表示该函数是有参函数;
(2)、函数名称遵循标识符命名规范;
(3)、自定义函数尽量放在 main 函数之前,如果要放在main函数后面的话, 需要在main函数之前先声明自定义函数,声明格式为:
[数据类型说明] 函数名称([参数]);
3、有参与无参
(1)在函数中不需要函数参数的称之为无参函数,在函数中需要函数参数的称之为有参函数。
区别:
函数()中多一个参数列表
4、形参与实参
(1)形参是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
特点:形参只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。
(2)实参是在调用时传递该函数的参数。
特点:实参可以是常量、变量、表达式、函数等。
注意:
在参数传递时,实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配的错误。
5、函数的调用
我们需要用到自定义的函数的时候,就得调用它,那么在调用的时候就称之为函数调用。
在C语言中,函数调用的一般形式为:
函数名([参数]);
二、递归函数
1、递归就是一个函数在它的函数体内调用它自身。
执行递归函数将反复调用其自身,每调用一次就进入新的一层.
特点:
(1)每一级函数调用时都有自己的变量,但是函数代码并不会得到复制,如计算5的阶乘时每递推一次变量都不同;
(2)每次调用都会有一次返回,如计算5的阶乘时每递推一次都返回进行下一次;
(3)递归函数中,位于递归调用前的语句和各级被调用函数具有相同的执行顺序;
(4)递归函数中,位于递归调用后的语句的执行顺序和各个被调用函数的顺序相反;
(5)递归函数中必须有终止语句。
三、局部与全局
1、局部函数
局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内, 离开该函数后再使用这种变量是非法的。在复合语句中也可定义变量,其作用域只在复合语句范围内。
2、全局变量
全局变量也称为外部变量,它是在函数外部定义的变量。它不属于哪一个函数,它属于一个源程序文件。其作用域是整个源程序。
四、变量的生存期
1、C语言根据变量的生存周期来划分,可以分为静态存储方式和动态存储方式。
(1)静态存储方式:是指在程序运行期间分配固定存储空间的方式。静态存储区中存放了在整个程序执行过程中都存在的变量.(extern、static)
(2)动态存储方式:是指在程序运行期间根据需要进行动态的分配存储空间的方式。动态存储区中存放的变量是根据程序运行的需要而建立和释放的,通常包括:函数形式参数;自动变量;函数调用时的现场保护和返回地址等。(auto、register)
2、分类
auto(可以省略)、register(寄存器变量,将局部变量放在CPU的寄存器)、extern(外部变量,可以调用在该函数之后定义的变量)、static(静态变量,静态局部变量在编译时赋初值,即只赋初值一次)
十二、指针
一、概念
指针也就是内存地址,指针变量是用来存放内存地址的变量。
二、指针变量的定义
1、变量在使用之前必须先定义.
形式:
类型标识符 *指针变量名;
2、地址与指针运算符
(1)地址运算符&
如果p是指针变量,a是整型变量 p=&a;
(2)指针运算符*
如果p是指针变量,a是整型变量 a=*p;
C标准库
一、<stdio.h>
二、<math.h>
sqrt(x)返回x的平方根
fabs(x)返回x的绝对值
pow(double x, double y)返回x 的 y 次幂
三、<stdlib.h>
int rand(void) 返回一个0到RAND_MAX之间的伪随机数
void srand(unsigned int seed)由函数rand使用的随机数发生器
四、<string.h>