目录
2.2.3 整型的大小和取值范围 short、int、long、 long long
一、C语言概述
1.1 C语言发展史
C语言源自于B、BCPL两种语言
C语言之父:丹尼斯·麦卡利斯泰尔·里奇(英语:Dennis MacAlistair Ritchie,1941年9月9日-2011年10月12日)
BCPL语言之父:马丁·理察德(Martin Richards,1940年7月21日-)英国
B语言之父:肯尼斯·蓝·汤普逊(英语:Kenneth Lane Thompson,1943年2月4日-)
1.2 C语言的特点
1)优点:
代码量小、执行速度快、功能强大、编程自由
2)缺点:
写代码实现周期长、可移植性较差、过于自由,经验不足容易出错、对平台库依赖较多
1.3 第一个C语言程序
#include <stdio.h>
//用include 导入文件,
//stdio.h std是一个标准库,io输入输出库 h表示头文件,用printf的时候需要这个库
//<>表示导入系统文件 ""表示导入自定义文件
// main() 函数为主函数,是程序中的唯一入口,int 表示返回值类型,()括号里可以填如需要的参数
int main()
{
// 行注释
/*
块注释
*/
printf("Hello world!\n"); //\n是一个转义字符,表示换行
return 0;
}
1.4 System函数的使用
功能:在已经运行的程序中执行另外一个外部程序
参数:外部可执行程序的名字
返回值: 成功0, 失败为其他任意数字
#include <stdlib.h>
int main(void)
{
//cmd命令 calc:计算器 notepad 记事本 mspaint 画图板……
system("calc"); //打开计算器
//可以打开一个外部的应用程序 如果带路径,需要使用\\或者/
system("D:\\Desktop\\QQ.exe");
return 0;
}
1.5 C语言的编译过程
C程序编译步骤:
1)预处理:宏定义展开、头文件展开、条件编译等,同时将代码中的注释删除,这里不会检查语法
2)编译:检查语法,将预处理后文件编译生成汇编文件
3)汇编:将汇编文件生成目标文件(二进制文件)
4)链接:C语言写的程序是需要依赖各种库的,所以编译之后还需要把库链接到最终的可执行程序中去
预处理: | gcc | -E | hello.c | -o | hello.i |
编译: | gcc | -S | hello.i | -o | hello.s |
汇编: | gcc | -c | hello.s | -o | hello.o |
链接: | gcc | hello.o | -o | hello |
选项 | 含义 |
-E | 只进行预处理 |
-S | 只进行预处理和编译 |
-c | 只进行预处理、编译、汇编 |
-o file | 指定生成的输出文件名为file |
一步编译:gcc -o hello.exe hello1.c hello2.c
常见代码问题:
- 编辑时异常
- 编译时异常
- 运行时异常
1.6 断点和单步调试
断点:在选中的行前 点击或按F9
调试程序:在“调试”中选择“开始调试”或按F5
逐语句执行:F11
逐过程执行:F10
跳出过程:shift+F11
停止调试:shift+F5
二、数据类型
2.1 数据类型概述
2.1.1 关键字32个
数据类型关键字(12个)
- char, short, int, long, float, double
- unsigned(无符号数), signed(有符号数)
- struct(结构体), union(联合体), enum(枚举)
- void(空类型)
控制语句关键字(12个)
- if, else, switch, case, default
- for, do, while, break, continue, goto, return
2.1.2 数据类型
⭐注意:
1. 在C语言中没有字符串类型,使用字符数组char[]表示字符串
2. 在不同系统上,部分数据类型字节长度不一样,举例:int可以占两个字节或4个字节
⭐数据类型的范围:
⭐C语言变量的生命周期和作用域
变量类型 | 生存周期 | 作用域 |
局部变量 | auto:自动变量,离开定义函数立即消失 | 只作用于函数内部 |
register:寄存器变量,离开定义函数立即消失 | ||
static:静态变量,离开定义函数仍然存在 | ||
全局变量 | 在程序运行期间一直存在 | static:静态变量,仅用于本文件内部调用 |
extern:外部存储变量,用于声明本文件将要用到的其他文件的变量 |
2.1.3 常量
⭐定义常量的方式:
- const 数据类型 常量名 = 值; (eg: const int PAI = 3.14;)
- #define 常量名 值 (eg: #define PAI = 3.14)
在C语言中,第一种方式是不安全的,C++中是安全的,推荐用第二种方式
枚举常量:
int main()
{
enum Sex
{
//枚举常量 性别
MALE,
FEMALE,
SELECT
};
enum Sex s = FEMALE; //利用枚举常量给变量赋值
printf("%d\n", MALE);
return ;
}
- 不能对枚举常量赋值,只能将他们的值赋给其他的变量
- 不能再定义与枚举常量名字相同的变量
- 不能用 & 取他们的地址
2.1.4 变量
⭐变量的定义方式
- 数据类型 变量名 = 值或表达式;(eg: int num = 3*5;)
再定义变量时,可以再数据类型前边加修饰auto,也可以不加
标识符命名规则:
- 不能使用系统关键字
- 允许使用字母、数字、下划线_
- 不允许数字开头,只能是字母或下划线开头
- 区分大小写
2.2 整型
2.2.1 整型变量的定义和输出
打印格式 | 含义 |
%d | 输出一个有符号的十进制int类型 |
%o | 输出8进制的int类型 |
%x | 输出16进制的int类型,字母以小写输出 |
%X | 输出16进制的int类型,字母以大写输出 |
%u | 输出一个10进制的无符号数 |
有符号数和无符号数:
#include <stdio.h>
int main(void)
{
//无符号 unsigned 有符号 signed(可以省略)
signed int a = -10;
unsigned int b = 10;//只能是正数,如果是负数,输出会是别的乱的数
printf("%d\n", a);
printf("%u\n", b);
return 0;
}
2.2.2 整型输入
用scanf 可以从标准输入流stdin 读取输入
scanf("%d", &a);
scanf 安全问题的两种解决方式:
- #define _CRT_SECURE_NO_WARNINGS //这个宏定义最好放到c文件的第一行
- #pragma warning(disable:4993) //或者使用这个,这个不用必须第一行
注意:在读取字符串时,只要遇到一个空格,scanf() 就会停止读取
#define _CRT_SECURE_NO_WARNINGS //用scanf时,忽略警告,这个宏定义最好放到c文件的第一行
#pragma warning(disable:4993) //或者使用这个,这个不用必须第一行
#include <stdio.h>
int main(void)
{
int a;
//通过键盘输入赋值
//&运算符,表示地址运算符
scanf("%d", &a);
printf("%d\n", a);
return 0;
}
2.2.3 整型的大小和取值范围 short、int、long、 long long
数据类型 | 占用空间 |
short(短整型) | 2字节 |
int(整型) | 4字节 |
long(长整型) | windows为4字节,Linux为4字节(32位),8字节(64位) |
long long(长长整型) | 8字节 |
注意:
- 数据类型不同,开具大小也不同
- 整型数据在内存中占的字节数与所选择的操作系统有关。虽然C语言标准中没有明确规定整型数据的长度,但long类型证书的长度不能短于int类型,short类型数据的长度不能长于int类型
- 当一个小的数据类型赋值给一个大的数据类型,不会出错,因为编译器会自动转换,但当一个大的数据类型赋值给一个小的数据类型,会丢失高位。
- short <= int <= long <= long long
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
int main()
{
int a = 10; //整型变量
short b = 20;//短整型变量
long c = 30;//长整型变量
long long d =40;//长长整型变量
printf("%d\n", a);
printf("%hd\n", b); //%hd 短整型数据占位符
printf("%ld\n", b); //%hd 长整型数据占位符
printf("%lld\n", b); //%hd 长长整型数据占位符
/* 整形大小的计算 sizeof
sizeof 计算数据类型再内存中占的字节(BYTE)大小
1B=8bit
三种格式:sizeof(数据类型) sizeof(变量名) sizeof 变量名
*/
unsigned int len = sizeof(int); //第一种格式
printf("整型:%d\n", len); //4 整型占的大小是4个字节
//第二种格式:
printf("整型:%d\n", sizeof(a)); //4B = 32bit
printf("短整型:%d\n", sizeof(b)); //2
printf("长整型:%d\n", sizeof(c)); //4
printf("长长整型:%d\n", sizeof(d)); //8
return EXIT_SUCCESS;
}
2.3 sizeof 关键字
用sizeof(data type)可以计算数据类型的大小
- sizeof不是函数,不需要任何头文件,它的功能是计算一个数据类型的大小,单位是字节
- sizeof的返回值是size_t
- size_t类型在32位操作系统下是 undesigned int 是一个无符号数
具体代码示例见 2.5
2.4 字符型:char
2.4.1 字符串变量的定义和输出
char ch = 'a';
%c 占位符来代表 char类型
2.4.2 字符串变量的输入
scanf("%c", &ch1);
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<math.h>
#include<stdio.h>
#include<string>
int main()
{
//2.4.1 字符型变量
char ch = 'a';
//打印字符型变量
printf("%c\n", ch); //a
//打印字母a对应十进制数(ASCⅡ码对应十进制代码)
printf("%d\n", ch); //97
//打印字符型大小
printf("字符型大小:%d\n", sizeof(ch)); //1
printf("%c\n", ch - 32) //A
printf("%c\n", 201) //?
//2.4.2 字符串的输入
char ch1;
scanf("%c", &ch1);
print("%c\n", ch1 - 32);
return EXIT_SUCCESS;
}
2.4.3 转义字符
转义字符 | 含义 | ASCⅡ码值(十进制) |
\a | 警报 | 007 |
\b | 退格(BS),将当前位置移到前一列 | 008 |
\f | 换页(FF),将当前位置移到下页开头 | 012 |
\n | 换行(LF),将当前位置移到下一行开头 | 010 |
\r | 回车(CR),将当前位置移到本行开头 | 013 |
\t | 水平制表(HT),(跳到下一个TAB位置) | 009 |
\v | 垂直制表(VT) | 011 |
\\ | 代表一个反斜线字符“\” | 092 |
\' | 代表一个单引号字符 | 092 |
\" | 代表一个双引号字符 | 034 |
\? | 代表一个问号 | 063 |
\0 | 数字0 | 000 |
\ddd | 8进制转义字符,d范围0-7 | 3位8进制 |
\xhh | 16进制转义字符,h范围0-9,a-f, A-F | 3位十六进制 |
注意:红色字体表注的为不可打印字符
eg: printf("\"你好\""); //"你好" \"输出 双引号
printf("20%%"); //30% 俩百分号输出一个百分号
2.5 实型(浮点型):float、double
双精度浮点型(double)比 单精度浮点型(float)更精确
占位符 %f 表示输出一个浮点型, 默认保留6位小数,C语言四舍五入
int main(void)
{
//传统方法赋值
long a = 20L; //L可以省略
float b = 3.14f; //或3.14F
double c = 3.14; //不以f结尾的 是double类型
printf("%.2f\n", b); //3.14 保留两位小数
printf("lf", c); //3.140000
//科学法赋值
a1 = 3.2e3f; //3.2*10^3=3200, e可以写成E
b1 = 3.2e-3f; //3.2*10^-3 = 0.0032
c = 3200;
//占位符 %f 表示输出一个浮点型, 默认保留6位小数,C语言四舍五入
printf("%f\n", a1); //3200.000000
printf("%e\n",c); //%e占位符表示用科学计数法表示
a2 = 3,1415926f;
printf("%f\n", a2); //结果为3.141593
//sizeof字节大小
//浮点型数据,存储在内存中的格式分别为符号位、指数位、小数位
printf("%d\n", sizeof(float)); //4
printf("%d\n", sizeof(double)); //8
return EXIT_SUCCESS;
}
%p 占位符 表示一个指针,以十六进制显示数据对应的内存地址
int main(void)
{
int a = 10;
float b = 3.14;
//%p 占位符 表示一个指针,以十六进制显示数据对应的内存地址
printf("%p\n", &a); //0097FD54
printf("%p\n", &b); //0097FD58
getchar();
return 0;
}
2.6 进制
bit和Byte
术语 | 含义 |
bit (比特) | 一个二进制数代表一位,一个位只能表示0或1两种状态,数据传输以“位"(bit)为单位 |
Byte (字节) | 一个字节为8个二进制,是计算机的最小存储单元 |
C语言如何表示相应的进制数
十进制 | 以正常数字1-9开头,如123 |
八进制 | 以数字0开头,如0123 |
十六进制 | 以0x开头,如0x123 |
二进制 | C语言不能直接书写二进制数 |
进制的转换输出:
int main(void)
{
//进制
//二进制0-1 八进制0-7 十六进制0-9 a-f
int a = 10;
printf("%d\n", a); //10
printf("%x\n", a); //十六进制 A
printf("%o\n", a); //八进制 12
int b = 0123; //定义八进制数据 以0开头
int c = 0x123; //定义十六进制数据,以0x开头
//在计算机定义数据时,不可以直接定义二进制
printf("%d\n", b); //二进制 83
printf("%x\n", b); //十六进制 53
printf("%o\n", b); //八进制 123
printf("%d\n", c); //二进制 291
printf("%x\n", c); //十六进制 123
printf("%o\n", c); //八进制 443
}
2.7 类型限定符
限定符 | 含义 |
extern | 声明一个变量,extern声明的变量没有建立存储空间。 extern int a; //变量在定义的时候创建存储空间 |
const | 定义一个常量,常量的值不能修改。 const int a = 10; |
volatile | 防止编译器优化代码 |
register | 定义寄存器变量,提高效率。register是建议型的指令,而不是命令型的指令,如果CPU有空闲寄存器,那么register就生效,如果没有空闲寄存器,那么register无效。· |
2.8 字符串格式化输出和输入
2.8.1 字符串常量
字符串是内存中一段连续的char空间,以'\0'(数字0)结尾
字符串常量是由双引号括起来的字符序列,如“china”、"C program"、"$12.5"等都是合法的字符串常量。
每个字符串的结尾,编译器都会自动添加一个结束标志位'\0'。
关于字符串的更多介绍可以参考5.5字符串
int main()
{
char a = 'a';
char * b = "a";
char * c = "a\0";
char * d = "hello\0 world";
char * b[11] = "hello world\0";
// 占位符%s 表示输出一个字符串,遇到\0停止,没\0的话,后边会乱码
printf("%s\n", d); // hello
return EXIT_SUCCESS;
}
2.8.2 printf函数 和 putchar函数
printf是输出一个字符串,putchar输出一个char
⭐printf格式字符:
打印格式 | 数据类型 | 含义 |
%d | int | 接受整数值并将它表示为有符号的十进制数 |
%hd | short int | 短整数 |
%hu | unsigned int | 无符号短整数 |
%o | unsigned int | 无符号8进制整数 |
%u | unsigned int | 无符号10进制整数 |
%x, %X | unsigned int | 无符号16进制整数,x对应小写,X对应大写 |
%f | float | 单精度浮点数 |
%lf | double | 双精度浮点数 |
%e,%E | double | 科学计数法表示的数,e/E表示 输出的e 是大写或小写 |
%c | char | 字符型,可以把输入的数字按照ASCⅡ码转为相应字符 |
%s | char * | 字符串,输出字符串中的字符直至字符串中的空字符(以‘\0’结尾) |
%p | void * | 以16进制形式输出指针 |
%% | % | 两个百分号 输出一个百分号 |
printf附加格式:
字符 | 含义 |
l (字母l) | 附加在d,u,x,o前,表示长整数 |
- | 左对齐 |
m (代表一个整数) | 数据最小宽度为m |
0 (数字0) | 将输出的前面补上0直到占满指定列宽为止,不可以搭配使用- |
m.n(代表一个整数) | m指域宽,即对应的输出项在输出设备上所占的字符数。n指精度,用于说明输出的实型数的小数位数,对数值型的来说,未指定n时,隐含的精度为n=6位 |
int main()
{
//printf输出字符串
int a = 10;
int b = 123456;
printf("===%5d===",a); //=== 10=== 默认右对齐,数据占5位
printf("===%-5d===",a);//===10 === 左对齐,数据占5位
printf("===%05d===",a); //===00010=== 右对齐,数据占5位,前空位补0
printf("===%05d===",b);//===123456===
float c = 3.14;
printf("===%7.2f===",a); //=== 3.14=== 右对齐,数据占7位,保留两位小数,小数点占一位
//putchar输出一个char
char ch = 'a';
//printf("%c\n", ch);
//putchar输出字符 可以是变量 字符 数字 转义字符
putchar(ch);
return 0;
putchar('B');
putchar(97);
putchar('\n');
return 0;
}
2.8.3 scanf函数和getchar函数
getchar是从标准输入设备读取一个char
scanf通过%转义的方式可以得到用户通过标准输入设备输入的数据
int main()
{
char ch1;
char ch2;
char ch3;
int a;
int b;
//getchar()接受键盘获取字符
printf("请输入ch1的字符:");
ch1 = getchar(); //获取字符
printf("ch1=%c\n",ch1);
getchar(); // 写上这行代码,可以用于暂时停留界面
//scanf作用
scanf("%d%d", &a, &b);
scanf("%d,%d", &a, &b); //中间可以加分隔符,但是不能是\n
scanf("%3d%d", &a, &b); //3表示接受3个数据(这个约束只能对整形)
printf("%d\t%d", a, b);
return EXIT_SUCCESS;
}
三、运算符与表达式
3.1 运算符优先级
1、() []取数组下表 . 取对象属性 -> 指针
2、- 取负数、~按位取反、++ 、--、!、sizeof 、(数据类型)强制类型转换 ,结合性从右到左,单目
3、*、/、%
4、+、-
5、<< 左移、>>右移
6、>、>=、<、<=
7、==、!=
8~10、 & 按位与、^ 按位异或、| 按位或
11、&& 逻辑与
12、|| 逻辑或
13、?: 三目运算符
14、=、+=、-=、*=、/=
15、, 逗号运算符,会将最后一个,的值赋值给前边的内容
int main()
{
int a = 10;
int b = 20;
int c = (a, b+20);
printf("%d\n",c); //40
return 0;
}
3.2 类型转换
转换的两种方式:
- 自动转换(隐式转换):遵循一定的规则,由编译系统自动完成。
- 强制类型转换:把表达式的运算结果强制转换成所需的数据类型
类型转换的原则:
占用内存字节数少的类型,向占用内存字节数多的类型转换
int main()
{
float p = 3.567;
int w = 2;
//隐式转换
double sum = p*w;
//(数据类型) 强制类型转换运算符 不会四舍五入
int sum2 = (int)p * w; //6
int sum2 = (int)(p*w); //7
}
四、程序流程结构
C语言的三种基本程序运行结构:顺序结构、选择结构、循环结构
4.1 选择结构
4.1.1 if语句
if 语句可以分为以下三种:
if(表达式){}
if(表达式){} else{}
if(表达式1){} else if(表达式2){} else{}
同时,if也可以进行嵌套。不同的示例代码如下所示:
int main()
{
int score;
scanf("%d", &score);
//if…else语句
//if(表达式){}
//if(表达式){}else{}
if (score >= 60)
{
printf("考试合格");
}
else
{
printf("考试成绩不合格");
}
//if…else if…else语句
//if(表达式1){} else if(表达式2){} else{}
if (score>=80){
printf("良好");
}
else if(score >= 60)
{
printf("及格");
}
else
{
printf("不及格");
}
//if条件嵌套
if (score>=80){
if(score>=90){
printf("优秀");
}
else
{
printf("良好");
}
}
else if(score >= 60)
{
printf("及格");
}
else
{
printf("不及格");
}
}
4.1.2 三目运算符 ?:
三目运算符的格式:
表达式1?表达式2:表达式3
if 表达式1 true -->表达式2, 如果表达式1 false -->表达式3
#define MAX(a,b) (a)>(b)?(a):(b)
int main()
{
int a =10;
int b = 20;
int c;
int d;
c = a > b ? a : b; // 三目运算符
printf("最大值为:%d\n", a > b ? a : b);
printf("最大值为:%d\n", MAX(a,b));//通过重定义函数来比较
}
4.1.3 switch语句
switch效率比if会高一些,多用于游戏的程序控制
测试switch() 括号中的表达式的值,等于哪个case,就执行相应case后的代码,
遇到break时跳出switch,如果该case中没有break,则继续检查后边的case
default可以放在switch中的最后,用于上边所有case都没有满足的时候执行,
int main()
{
int score;
scanf("%d", &score);
switch (score/10)
{
case 10:
printf("优秀\n");
break;
case 9:
printf("优秀\n");
break;
case 8:
printf("良好\n");
break;
case 7:
printf("及格\n");
break;
case 6:
printf("及格\n");
break;
default: //这里存放其他情况
printf("不及格\n");
break;
}
return EXIT_SUCCESS;
}
4.2 循环语句
4.2.1 while 和 do...while
两种语句的格式如下
do{ } while(条件);
while(条件){ }
do...while是先执行一次,在判断循环,while是先判断在执行。相比来说,do...while一定会执行一次,但是while可以一次都不执行;
需要小心死循环的发生,在while语句中及时添加自增或自减语句
int main():
{
//while(表达式)
int i = 0;
while(i<10)
{
printf("%d\n", i);
i++; //没这个会死循环
}
//用while实现 逢7过
int a = 1;
while(a<100)
{
//7的倍数 || 个位数为7 || 十位数是7
if(a % 7 == 0 || a % 10 == 7 || a/10 == 7)
{
printf("过\n");
}
else
{
printf("%d\n", a);
}
}
//do while语句
int j = 0;
do
{
printf("%d\n",j);
j++;
} while(j < 10);
return EXIT_SUCCESS;
}
代码实例:水仙花数
//水仙花数 从100-999 各个位数的立方和相加等于这个数本身就是一个水仙花数
int main(void)
{
int i = 100;
do
{
//个位数
int a = i % 10;
//十位数
int b = i / 10 % 10;
//百位数
int c = i / 100 ;
if(a*a*a + b*b*b + c*c*c==i)
{
printf("%d是水仙花数\n", i);
}
i++;
} while(i <= 999);
return EXIT_SUCCESS;
}
4.2.2 for语句
for循环语法:
for ( init; condition; increment )
{
statement(s);
}
init 用来声明在循环控制变量,可以在for语句之前声明,在这里赋值,也可以直接声明赋值
condition 为循环判断条件,true时进入循环,false就不执行了,直接下一部分代码
increment 在每次循环结束后执行,更新控制变量,之后再进行condition的条件判断
代码实例:随机数
#include<stdlib.h>
#include<time.h>
#include<stdio.h>
int main()
{
//C99库
for(int i = 0; i < 10; i++)
{
printf("%d\n", i);
}
//产生随机数
//1、导入头文件 time.h stdlib.h
//2、添加随机数种子
//3、获取随机数
srand(unsigned int) time(NULL); //加上随机数中词,让每次随机数不一样
for (int i = 0; i<10;i++)
{
int value = rand()%10; //0-9的数,如果%100,就是取0-99的数
printf("%d\n", value);
}
return 0;
}
不同的循环都可以进行嵌套,用for循环嵌套实现时钟如下
int main()
{
//时钟
for(int i = 0; i<24; i++)
{
for(int j = 0; j<60;j++)
{
for (int k = 0; k < 60; k++)
{
System("cls");//清理屏幕
printf("%02d:%02d:%02d\n",i,j,k);
Sleep(960);
}
}
}
}
4.3 跳转语句
4.3.1 break、continue
break如果再嵌套语句中使用,跳出本层循环,
continue 用于中止本次循环,进入下一次
4.3.2 goto语句
int main(void)
{
printf("hello world1\n");
printf("hello world2\n");
goto FLAG;
printf("hello world3\n");
printf("hello world4\n");
printf("hello world5\n");
FLAG:
printf("hello world6\n");
printf("hello world7\n");
printf("hello world8\n");
printf("hello world9\n");
return EXIT_SUCCESS;
}
这是关于C语言的一部分学习笔记,后续也会持续更新,感谢您的支持和关注!❤️