什么是C语言?
C语言是一门通用计算机编程语言,广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。
二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSIC,作为C语言最初的标准。[1]目前2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。
语言是一门面向过程的计算机编程语言,与C++,|ava等面向对象的编程语言有所不同。其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、TurboC等。
第一个C语言程序
#include <stdio.h>
int manin()
{
printf("hello world"\n);
return 0;
}
//解释:
//main函数是程序的入口
//一个工程中main函数有且只有一个
数据类型数据类型
数据类型 | 名称 | 打印字符格式数据 |
char | 字符数据类型 | %c |
short | 短整型 | |
int | 整型 | %d |
long | 长整型 | |
long long | 更长的整型 | |
float | 单精度浮点数 | %f |
double | 双精度浮点数 | %lf |
printf输出变量:
%d
:用于输出有符号的十进制整数(int)%u
:用于输出无符号的十进制整数(unsigned int)%x
或%X
:用于输出无符号的十六进制整数(unsigned int),其中%x
输出小写字母,%X
输出大写字母%o
:用于输出无符号的八进制整数(unsigned int)%f
:用于输出浮点数(float 或 double)%e
或%E
:用于输出指数形式的浮点数(float 或 double),%e
使用小写e
,%E
使用大写E
%g
或%G
:用于输出浮点数,自动在%f
和%e
/%E
之间选择较短的输出形式(float 或 double)%c
:用于输出单个字符(char)%s
:用于输出字符串(char数组或字符指针)%p
:用于输出指针的值(任何类型的指针)
- C语言有没有字符串类型?
C语言没有专门的字符串类型,字符串是通过字符数组来实现的。
- 为什么出现这么多类型?
主要是因为:
精确性:不同的类型可以表示不同范围的数值,确保数据处理的精确性。
效率:使用合适的数据类型可以减少内存使用,提高程序运行效率。
硬件和平台:不同的硬件平台可能对数据类型的大小有不同的要求。
- 每种类型的大小是多少?
用代码来验证一下!
#include <stdio.h> int main() { printf("%d\n",sizeof(char)); printf("%d\n",sizeof(short)); printf("%d\n",sizeof(int)); printf("%d\n",sizeof(long)); printf("%d\n",sizeof(long long)); printf("%d\n",sizeof(float)); printf("%d\n",sizeof(double)); printf("%d\n",sizeof(long double)); }
char 1 short 2 int 4 long 4/8 long long 8 float 4 double 8 为什么long的大小有4有8呢?
这是取决于平台的,当sizeof(long)=sizeof(int),long就等于4.当当sizeof(long)>=sizeof(int),那么long等于8。
类型的使用:
char ch = 'w'; int weight = 120; int salary = 20000;
变量、常量
生活中的有些值是不变的(比如:圆周率、性别(?),身份证号码、血型等等)
有些值是可变的(比如:年龄、体重、薪资)。
不变的值,C语言中用常量的概念来表示,变得值,C语言中用变量来表示。
定义变量的方法
int age = 150;
float weight = 45.5f;
char ch = 'w';
变量的分类
- 局部变量
- 全局变量
#include <stdio.h>
int global = 7777; //全局变量
int main()
{
int local = 6666;
//下面定义的global会不会出问题?
int global = 5555;
printf("global = %d\n",global);
return 0;
}
答:上面局部变量的global变量定义是没有问题的
当局部变量和全局变量同名的时候,局部变量优先使用
变量的使用
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个数字空格隔开:>");
scanf("%d%d",&num1,&num2);
sum = num1 + num2;
printf("sum = %d\n",sum);
return 0;
}
输出语句scanf、printf
1. printf
函数用于在屏幕上输出格式化的字符串。它属于标准输入输出库stdio.h
,所以在使用前需要包含这个头文件。例如:
#include <stdio.h> int main() { printf("Hello, World!\n"); // 输出字符串 printf("整数:%d\n", 123); // 输出整数 printf("浮点数:%f\n", 3.14); // 输出浮点数 return 0; }
2.
scanf
函数用于从标准输入(通常是键盘)读取格式化的数据。同样,它也属于stdio.h
库。例如:
#include <stdio.h> int main() { int number; printf("请输入一个整数:"); scanf("%d", &number); // 读取一个整数到变量number中 printf("您输入的整数是:%d\n", number); return 0; }
注意:
- 对于基本数据类型(如
int
,float
等),需要传递变量的地址,因此使用&
运算符。scanf
在读取时会跳过空白符(空格、制表符、换行符等),直到遇到非空白符才开始读取。
变量的作用域和生命周期
在C语言中,变量的作用域(Scope)和生命周期(Lifetime)是两个重要的概念,它们定义了变量在程序中的可见性和存在时间。
作用域(Scope)
作用域(Scope),程序设计概念,通常来说,一段代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
1. 局部变量的作用域是变量所在的局部范围。
2. 全局变量的作用域是整个工程。
生命周期(Lifetime)
变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。
1. 局部变量的生命周期是进入作用域生命周期开始,出作用域生命周期结束。
2. 全局变量的生命周期是整个程序的生命周期
二更
常量
C语言中的常量和变量的定义的形式有所差异。
C语言中的常量分为以下几种:
- 字面常量
- const修饰的常变量
- #define定义的标识符常量
- 枚举常量
1. 字面常量
字面常量是直接出现在源代码中的固定值。它们可以是整数、浮点数、字符或字符串等。
- 整数常量:例如
123
,-456
,0
,0x1A
(十六进制)。- 浮点常量:例如
3.14
,-0.56
,1.0e-3
(科学记数法)。- 字符常量:例如
'A'
,'\n'
(换行符)。- 字符串常量:例如
"Hello, World!"
。2. const修饰的常变量
使用
const
关键字声明的变量称为常变量,它们的值在初始化后不能被修改。const
主要用于指定一个变量的值不应该被改变。const int MAX_SIZE = 100; // 声明一个常变量 // MAX_SIZE = 200; // 错误:不能修改常变量的值
3. #define定义的标识符常量
使用预处理指令
#define
可以定义标识符常量,它通常用于定义程序中多次使用的常量值。#define PI 3.14159 // 定义一个标识符常量 #define MAX_COUNT 100 // 定义另一个标识符常量 float radius = 5.0; float area = PI * radius * radius; // 使用标识符常量PI
#define
定义的标识符常量在编译时会被预处理程序直接替换为对应的值,不会占用内存空间。4. 枚举常量
枚举是一种用户定义的数据类型,它由一组命名的整数常量组成。每个枚举常量都代表一个整数值,默认情况下,第一个枚举常量的值为0,后续的每个枚举常量的值比前一个大1。
enum Weekday { MONDAY, // 默认为 0 TUESDAY, // 默认为 1 WEDNESDAY, // 默认为 2 THURSDAY, // 默认为 3 FRIDAY, // 默认为 4 SATURDAY, // 默认为 5 SUNDAY // 默认为 6 }; // 使用枚举常量 enum Weekday today = MONDAY;
枚举常量通常用于定义一组相关的常量,使程序更易于理解和维护。枚举常量的值可以在声明时指定:
enum Color { RED = 1, GREEN = 2, BLUE = 4 };
字符串+转义字符+注释
字符串
"hello world\n"
这种由双引号(double quote)引起来的一串字符称为字符串字面值(string literal),或者简称字符串。
注:字符串的结束标志是一个\0的转义字符,在计算字符串长度的时候\0是结束标志,不算做字符串内容。
打印字符串%s
例:
int main() { char arr1[] = "abc"; char arr2[] = "'a','b','c'"; printf("%s\n",arr1); printf("%s\n",arr2); return 0; }
#include <stdio.h> #include <string.h> // 包含strlen函数的声明 int main() { char arr1[] = "abc"; // 自动添加空字符 '\0' 作为字符串的结尾 char arr2[] = {'a', 'b', 'c'}; printf("%d\n", strlen(arr1)); // 输出应为 3 printf("%d\n", strlen(arr2)); // 输出应为 随机值 return 0; } // 用了strlen()函数需要引头文件---<string.h>
#include <stdio.h> #include <string.h> // 包含strlen函数的声明 int main() { char arr1[] = "abc"; // 自动添加空字符 '\0' 作为字符串的结尾 char arr2[] = {'a', 'b', 'c'}; // 手动添加空字符 '\0' 作为字符串的结尾 printf("%d\n", strlen(arr1)); // 输出应为 3 printf("%d\n", strlen(arr2)); // 输出应为 3 return 0; }
转义字符
假如我们要在屏幕上打印一个目录:c:\office\wps
怎用用代码表示?
这样?yes他是错的!
int main() { printf("c:\office\64\wps"); return 0; }
酱紫?才是对的!
int main() { printf("c:\\office\\64\\wps"); return 0; }
酱紫?也是对的!
int main() { printf("c:/office/64/wps"); return 0; }
C语言中的转义字符!
转义字符 释义 \?(淘汰 ) 在书写连续多个问号时使用,防止他们被解析成三字母词 \' 用于表示字符常量' \" 用于表示一个字符串内部的双引号 \\ 用于表示一个反斜杠,防止它被解释为一个转义序列符 \a 警告字符,蜂鸣 \b 退格符 \f 换页符 \n 换行 \r 回车 \t 水平制表符 \v 垂直制表符 \ddd ddd表示1-3个八进制的数字。如:\130X \xdd dd表示2个十六进制数字。如:\x30 0
三更
那么我们来猜猜该代码返回长度几呢?
#include <stdio.h> #include <string.h> // 包含strlen函数的声明 int main() { printf("%d\n",strlen("c:\test\32\test.c")); return 0; }
正确答案:13,怎么数的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 c : \t e s t \32 \t e s t . c \t是制表符只占1位 ,\32表示一个八进制数字也只占一位!这两个都是转义字符
32作为8进制代表的那个十进制数字,作为ASCII码值,对应的字符
32-->10进制26-->作为ASCII码代表的字符,于是对照一下就代表的是→
扩展一下ascll码:需要记住0对应48、A对应65、a对应97。依次递增1
思考:
- 在屏幕上打印一个单引号'该怎么做?
- 在屏幕上打印一个字符串,字符串内容是一个双引号"该怎么做?
int main() { printf("%c\n",'\''); printf("%s\n","\""); return 0; }
聪明的你~答了吗~
注释
- 代码中有不需要的代码可以直接删除,也可以注释掉
- 代码当中有些代码比较难懂,可以加一下注释文字
注释有两种方式:
- C语言的注释:/*.............*/
缺陷:不能嵌套注释
- C++的注释://...................
可以注释一行也可以注释多行
选择语句
if语句
在C语言中,提供三种形式的if语句。
1. 单分支if语句
if语句形式:
if(表达式)语句S
流程图示意:
执行过程:系统首先计算表达式的值,如果表达式结果不为0,则执行语句S;否则跳过语句S,继续执行其后的其他语句。
(1)“if”是C语言的关键字;“表达式”是任意合法的C语言表达式,可以是关系表达式或逻辑表达式,也可以是任意的数值类型(包括整型、实型、字符型等);表达式两侧括号不可以省略。
(2)语句S可以是一条语句,也可以是任意合法的复合语句,其位置比较灵活,可以直接出现在if同一行的后面,也可以出现在if的下一行。如果语句S只是一条语句,可以直接写,也可以加上{},如果是多条语句一定要用{}把这些语句括起来。
举个栗子
#include <stdio.h> #include <stdlib.h> int main() { // 输入一个整数n int n = 0; scanf("%d", &n); // 如果n小于0,则转换为它的绝对值 if (n < 0) { n = -n; // 更简洁的负数转正数的方式 } // 输出绝对值 printf("%d\n", n);
2. 双分支语句
if...else语句形式
if(表达式)语句S1
else 语句S2
流程图示意:
执行过程:系统首先计算表达式的值,如果结果不为0,则执行语句S1;否则,执行语句S2。
选择结构全部执行完成后继续执行其后的其他语句。
举例:
#include <stdio.h> #include <stdlib.h> int main() { int x, y = 0; scanf("%d", &x); if (x < 0) y = x * -1; else y = x; printf("%d", y); return 0; }
3. 多分支语句
if...else if...else语句形式
if(表达式1)语句S1
...
else if(表达式n)语句Sn
else 语句Sn+1
流程图示意:
执行过程:if - else-if 结构实际上是由多个if-else 结构组合而成的,系统首先计算表达式1,其值不为0时,执行语句S1;否则计算表达式2,其值不为0时,执行语句S2;......如果if 后的所有表达式都不为真,则执行语句Sn+1,并结束整个分支结构。
4. if语句的嵌套
if 语句的嵌套是指if 或 else 子句中又包含一个或多个if 语句。其实就是语句S为一个if语句。
形式较多就不一一例举了。
嵌套选择结构主要用于处理多条件的问题。设计嵌套选择结构时应清晰描述各条件之间的约束关系。在使用时要特别注意以下两点:
(1)if 与 else 的配对关系。内嵌结构中,else 总是与它上面最近的、未配对的 if 配对,组成一对 if-else。
(2)如果 if 与 else 的数目不一样,为了避免在 if 与 else 配对时出错,建议使用“{}”来限定内嵌if语句的范围。
如:
if (表达式1)
{if (表达式2) 语句1}
else 语句2
循环语句
C语言中如何实现循环呢?
- while循环
- for循环
- do...while循环
while循环
while循环根据给定条件的真假来重复执行一段代码块,知道条件变为假为止
流程图示意:
while循环简单的可以记为:只要当循环体表达式为真(即给定的条件成立),就执行循环体语句。
- 注意:while循环的特点是先判断条件表达式,后执行循环体
int main() { int i = 0; while (i < 20){ printf("好好学习!%d\n",i); i++; } if (i >= 20) printf("厉害"); return 0; }
do...while循环
do...while循环与while循环类似,不同之处在于do...while循环至少会执行一次代码块,然后根据条件的真假来决定是否再次执行。
流程图示意:
注意:do...while的特点是,先无条件的执行循环体,然后判断循环体是否成立。
#include <stdio.h> #include <stdlib.h> int main() { int i = 0; // 初始化计数器 // do...while 循环至少执行一次循环体 do { printf("第 %d 次执行循环。\n", i + 1); i++; // 更新计数器 } while (i < 5); // 条件判断在循环体之后 printf("循环结束。\n"); return 0; }
循环先浅显的学学while
函数
函数分为库函数和自定义函数
1: C语言为我们提供了上百个可调用的库函数,例如与字符串有关的 strlen, strcat, strlwr .
或是我们刚接触C语言时候用到的 printf, scanf,
这些都是c语言为我们提供的。在我们使用某一库函数的时候,需要在程序中嵌入(#include<>) 该函数所需要的头文件。 这也就是为啥我们在代码开头都需要写上#include <stdio.h>
,因为 printf, scanf,getchar,gets,putchar()
这些函数 (也称作标准I/O函数),都是在stdio头文件中。
2:自定义函数就是我们自己写的
arr()
#include <stdio.h>
int Add(int x,int y){
int z = x+y;
return z;
}
int main() {
int num1 = 10;
int num2 = 20;
int sum = 0;
int a = 100;
int b = 200;
sum = Add(num1,num2);
sum = Add(a,b);
printf("sum=%d\n",sum);
return 0;
}
函数的特点就是简化代码,代码复用
max()
#include <stdio.h>
int Max(int num1,int num2);
int main() {
int a = 0;
int b = 0;
int c;
scanf("%d%d",&a,&b);
c = Max(a,b);
printf("最大数是:%d\n",c);
return 0;
}
int Max(int num1,int num2){
int num3;
if (num1 > num2){
num3 = num1;
}else{
num3 = num2;
}
return num3;
}
数组
要存储1-10的数字,怎么存储?
C语言中给了数组的定义:一组相同类型元素的集合
数组的定义
定义数组,第一个维度可以省略,第二个不可以省略
下列各定义数组的语句中不正确
的是(C)
A.int a[1][3];
B.int x[2][2]={1,2,3,4};
C. int x[2][]=[1,2,4,6};
D.int m[][3]={1,2,3,4,5};
#include <stdio.h>
int main() {
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整型数组,最多放10个元素
//arr[4];
printf("%d\n",arr[4]);
return 0;
}
下标默认从0开始,也就是说最大的数字为n时,最大的下标为n-1。用下标形式访问元素
当想打印数组全部内容时,可以搭配while函数使用:
#include <stdio.h>
int main() {
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//定义一个整型数组,最多放10个元素
int i = 0;
while(i < 10){
printf("%d\n",arr[i]);
i++;
}
//printf("%d\n",arr[4]);
return 0;
}
操作符
算术操作符 | + | 加 |
- | 减 | |
* | 乘 | |
/ | 除 | |
% | 模 | |
移位操作符 | >> | 右移操作符 |
<< | 左移操作符 | |
位操作符 | & | 按位与 |
^ | 按位或 | |
| | 按位异或 | |
赋值操作符 | = | 等于 |
+= | 加等于 | |
-= | 减等于 | |
*= | 乘等于 | |
/= | 除等于 | |
&= | 与等于 | |
^= | 异或等于 | |
|= | 或等于 | |
>>= | 右移等于 | |
<<= | 左移等于 | |
单目操作符 | ! | 逻辑反操作 |
- | 负值 | |
+ | 正值 | |
& | 取地址 | |
sizeof | 操作数类型长度(以字节为单位) | |
~ | 对一个数的二进制按位取反 | |
-- | 前置、后置-- | |
++ | 前置、后置++ | |
* | 间接访问操作符(解引用操作符) | |
(类型) | 强制类型转换 | |
关系操作符 | > | |
>= | ||
< | ||
<= | ||
!= | 用于测试“不相等” | |
== | 用于测试“相等” | |
逻辑操作符 | && | 逻辑与 |
|| | 逻辑或 | |
条件操作符 | exp1 ? exp2 : exp3 | |
逗号表达式 | exp1 , exp2 , exp3 , ...expn | |
下标引用,函数调用和结构成员 | [] | |
() | ||
. | ||
-> |
算术操作符
算术操作符 | + | 加 |
- | 减 | |
* | 乘 | |
/ | 除 | |
% | 模 |
- /(除)
#include <stdio.h>
int main() {
int a = 5/2; //商2余1,取商
printf("%d\n",a);
return 0;
}
- %(模)
#include <stdio.h>
int main() {
int a = 5%2; //取模,得到的是余数为1
printf("%d\n",a);
return 0;
}
移(2进制)位操作符
移位操作符 | >> | 右移操作符 |
<< | 左移操作符 |
- <<(左移操作符)
- >>(右移操作符)
#include <stdio.h>
int main() {
int a = 1;
//整型1占4字节--32bit位,那么1也就是00000000000000000000000000000001,
//左移1位也就是左边0丢弃,右边补0,00000000000000000000000000000010--等于2
int b = a<<1;
printf("%d\n",b);
return 0;
}
(2进制)位操作符
位操作符 | & | 按位与 |
^ | 按位或 | |
| | 按位异或 |
- &按位与--and
- |按位或--or
- ^按位异或--not
按位与&
#include <stdio.h>
int main() {
int a = 3;
int b = 5;
int c = a&b;
//3--011
//5--101
//全1为1,所以为001,转换10进制为1
printf("%d\n",c);
return 0;
}
按位或|
#include <stdio.h>
int main() {
int a = 3;
int b = 5;
int c = a|b;
//011
//101
//111,有1及为1,转换为10进制为7
printf("%d\n",c);
return 0;
}
按位异或^
#include <stdio.h>
int main() {
int a = 3;
int b = 5;
int c = a^b; //异或的计算规律:对应的二进制位相同为0,不同为1
//011
//101
//110,有1即为1,转换为10进制为6
printf("%d\n",c);
return 0;
}
赋值操作符
赋值操作符 | = | 等于 |
+= | 加等于 | |
-= | 减等于 | |
*= | 乘等于 | |
/= | 除等于 | |
&= | 与等于 | |
^= | 异或等于 | |
|= | 或等于 | |
>>= | 右移等于 | |
<<= | 左移等于 |
复合赋值符:-+ 、-=、*=、/=、%=、<<=、>>=、&=、|=、^=
#include <stdio.h>
int main() {
int a = 10;
a = 20; //=--赋值、==判断相等
a = a+10;
a += 10;
a = a-20;
a -= 20;
//计算过程:a被赋值为20,20+10=30,30+10=40,40-20=20,20-20=0
printf("%d\n",a);
return 0;
}
单目操作符(对应:双目操作符、三目操作符)
单目操作符 | ! | 逻辑反操作 |
- | 负值 | |
+ | 正值 | |
& | 取地址 | |
sizeof | 操作数类型长度(以字节为单位) | |
~ | 对一个数的二进制按位取反 | |
-- | 前置、后置-- | |
++ | 前置、后置++ | |
* | 间接访问操作符(解引用操作符) | |
(类型) | 强制类型转换 |
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
a+b;//左边一个操作数,右边一个操作数,所以又叫双目操作符
//顾名思义单目操作符只有一个操作数,双目两个,三目三个
printf("%d\n",a);
return 0;
}
!逻辑反操作符
#include <stdio.h>
int main() {
// C语言表示真假,0表示假,非0为真
int a = 10;
int b = 0;
printf("%d %d\n", a, b); // 打印变量a和b
// 在这里,因为b是0,所以!b的结果是1(真)
printf("%d %d\n", !a, !b); // 打印变量a和!b的结果
// 10为真,!就把它变成假也就是0
return 0;
}
sizeof
#include <stdio.h>
int main() {
int a = 10;
int arr[10] = {0};//十个整型元素的数组
//sizeof计算的是变量或者类型所占空间大小,单位是字节
printf("%d\n", sizeof(a)); //4
printf("%d\n", sizeof(int));//也可以这么写
printf("%d\n", sizeof a);//变量名时括号可以省略,int时不可
printf("%d\n", sizeof(arr));
return 0;
}
计算数组元素个数
#include <stdio.h>
int main() {
int arr[10] = {0};//十个整型元素的数组
int sz = 0;
//计算数组的元素个数
//个数=数组总大小/每个元素的大小
sz = sizeof(arr)/sizeof(arr[0]);
printf("%d\n", sizeof(arr));
printf("sz = %d\n",sz);
return 0;
}
~按位取反
#include <stdio.h>
int main() {
int a = 0;//4字节、占32bit
//00000000000000000000000000000000
//11111111111111111111111111111111
//原码、反码、补码
//原码--符号位不变其他位取反得到反码--反码+1得到补码
//负数在内存中存储的时候,存储的是二进制的补码
//最高位为1是负数,最高位为0是正数
//使用的,打印的是这个数的原码
//11111111111111111111111111111111
//11111111111111111111111111111110
//10000000000000000000000000000001
//结果为-1
int b = ~a;//b是有符号的整型
//~按(2进制)位取反
//例:1010
//取反:0101
printf("%d\n",b);
return 0;
}
只要是整数,内存中存储的都是二进制的补码(负数第一位为1,正数第一位为0)
正数-->原码、反码、补码三码统一,相同
负数-->存的是补码
原码:直接按照正负写出的二进制序列
反码:原码符号位不变,其他位按位取反
补码:反码+1
++
#include <stdio.h>
int main() {
int a = 10;
int b = a++;//后置++,先使用它的值,再让a++
//先把a++的结果赋值a,a的值赋给b
//a=11,b=10
int c = 10;
int d = ++c;//前置++,先++,再使用它的值
//如果c结果原来是10,先++变成11,再把11赋给b,b也就是11
printf("a=%d,b=%d\n",a,b);
printf("c=%d,d=%d\n",c,d);
return 0;
}
--
#include <stdio.h>
int main() {
int a = 10;
int b = a--;//后置--,先使用它的值,再让a--
//先把a--的结果赋值a,a的值赋给b
//a=9,b=10
int c = 10;
int d = --c;//前置--,先--,再使用它的值
//如果c结果原来是10,先--变成9,再把9赋给d,d也就是9
printf("a=%d,b=%d\n",a,b);
printf("c=%d,d=%d\n",c,d);
return 0;
}
(类型)--强制类型转换
让某一种类型,强制转换成另一种类型
#include <stdio.h>
int main() {
int a = (int)3.14;
return 0;
}
关系操作符
关系操作符 | > | |
>= | ||
< | ||
<= | ||
!= | 用于测试“不相等” | |
== | 用于测试“相等” |
逻辑操作符
逻辑操作符 | && | 逻辑与 |
|| | 逻辑或 |
&&逻辑与
#include <stdio.h>
int main() {
//C语言中,真--非0。假--0
//&&--逻辑与
int a = 3;
int b = 5;
int aa = 0;
int bb = 5;
int c = a && b;
int cc = aa && bb;
//a为真,b为真,a逻辑与b为真就为1
//aa为假,bb为真,aa逻辑与bb为假就为0
//有一个为假就为假
printf("%d\n",c);
printf("%d\n",cc);
return 0;
}
||逻辑或
#include <stdio.h>
int main() {
//C语言中,真--非0。假--0
//&&--逻辑与
int a = 3;
int b = 5;
int aa = 0;
int bb = 5;
int aaa = 0;
int bbb = 0;
int c = a || b;
int cc = aa || bb;
int ccc = aaa || bbb;
//a为真,b为真,a逻辑或b为真就为1
//aa为假,bb为真,aa逻辑或bb为真就为1
//aaa为假,bbb为假,aaa逻辑或bbb为假就为0
//全0才为0
printf("%d\n",c);
printf("%d\n",cc);
printf("%d\n",ccc);
return 0;
}
条件/三目操作符
条件操作符 | exp1 ? exp2 : exp3 |
#include <stdio.h>
int main() {
int a = 3;
int b = 5;
int max = 0;
max = (a > b ? a : b);
//如果a>b,执行a结果,否则执行b结果
printf("%d\n",max);
return 0;
}
逗号表达式
逗号表达式 | exp1 , exp2 , exp3 , ...expn |
下标引用、函数调用和结构成员
下标引用,函数调用和结构成员 | [] |
() | |
. | |
-> |
#include <stdio.h>
int Add(int x,int y){
int z = 0;
z = x + y;
return z;
}
int main() {
int arr[10] = {0};
arr[4];//[]下标引用操作符
int a = 10;
int b = 20;
int sum = Add(a,b);//()函数调用操作符
return 0;
}
常见关键字
auto(局部变量前都有一个auto关键字,但是因为局部变量都是自动变量,所以基本省略)、break、case、char、const、continue、default、do、double、else、enum、extern(用来声明外部符号)、float、for、goto、if、int、long、register(寄存器关键字)、return、short、signed(有符号)、sizeof、static、struct(结构体关键字)、switch、typedef、union(联合体【共用体】)、unsigned(无符号)、void(无、空)、volatile、while
注:先简单介绍几个,后面遇到再讲解
auto
每个局部变量都是auto修饰的,只不过省略了。
extern
用来声明外部符号
register
寄存器关键字
register int num = 100;
//建议将num值寄放在寄存器中
signed
有符号
unsigned
无符号(即全为正数)
union
联合体(共用体)
void
无、空
typedef
typedef顾名思义是类型定义,这里应该理解为类型重命名。
例:将unsigned int重命名为uint_32,所以uint_32也是一个类型名
#include <stdio.h>
typedef unsigned int uint_32;
int main(){
unsigned int num1 = 0;
uint_32 num2 = 0;
printf("%d%d\n",num1,num2);
return 0;
}
static
在C语言中static是用来修饰变量和函数的
- 修饰局部变量--静态局部变量
- 修饰全局变量--静态全局变量
- 修饰函数--静态函数
#include <stdio.h>
void test(){
int num = 1;
num++;//num就变成了2
printf("num = %d\n",num);//num输出2,进入a++中
}
int main(){
int a = 0;
while (a < 5){
test();
a++;//判断a<5,继续进入test函数中
}
printf("a = %d\n",a);
return 0;
}
修饰局部变量
static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。
#include <stdio.h>
//static修饰局部变量,局部变量的生命周期变长
void test(){
static int num = 1;//静态的局部变量
num++;
printf("num = %d\n",num);
}
int main(){
int a = 0;
while (a < 5){
test();
a++;
}
printf("a = %d\n",a);
return 0;
}
修饰全局变量
报错
一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用,不能在其他源文件内使用。
全局变量,在其他源文件内部可以被使用,是因为全局变量具有外部链接属性,但是被static修饰之后,就变成了内部链接属性其他源文件就不能链接到这个静态的全局变量了。
//1.1.c
int g_val = 2018;
//01.c
#include <stdio.h>
//static修饰全局变量,改变了变量的作用域
//让静态的全局变量只能在自己所在的原文件内部使用,出了原文件就无法使用
int main(){
//extern声明外部符号
extern int g_val;
printf("g_val = %d\n",g_val);
return 0;
}
//gcc 01.c 1.1.c -o 01.exe
//这里因为是两个文件,所以需要把两个.c文件包含到一个exe程序中才行,不然它检测不到你在另一个文件定义的全局变量
修饰函数
报错
一个函数被static修饰,使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
本质上,static是将函数的外部链接属性变成了内部链接属性,与static修饰全局变量一样。
//1.1.c
static int Add(int x,int y){
int z = x + y;
return z;
}
01.c
#include <stdio.h>
//static修饰函数,也是改变了函数的作用域(这种说法不准确)
//static修饰函数,也是改变了函数的链接属性()
//外部链接属性 --> 内部链接属性
//声明外部函数
extern int Add(int,int);
int main(){
int a = 10;
int b = 20;
int sum = Add(a,b);
printf("sum = %d\n",sum);
return 0;
}
//gcc 01.c 1.1.c -o 01.exe
//这里因为是两个文件,所以需要把两个.c文件包含到一个exe程序中才行,不然它检测不到你在另一个文件定义的全局变量
#define定义常量和宏
定义标识符常量
#include <stdio.h>
//#define定义的标识符常量
#define MAX 100extern int Add(int,int);
int main(){
int a = MAX;
//往后只要拿出MAX就通通替换为100
return 0;
}
定义宏
#include <stdio.h>
//#define可以定义宏--带参数
//函数的实现
int Max(int x,int y){
if(x>y)
return x;
else
return y;
}
//宏的定义
#define Max(X,Y) (X>Y?X:Y)
int main(){
int a = 10;
int b = 20;
//函数的方式
int max = Max(a,b);
printf("%d\n",max);
//宏的方式
max = Max(a,b);
//替换成这样max = (a>b?a:b);
printf("%d\n",max);
return 0;
}
指针
指针其实用来访问内存的,了解 指针 那我们就要先了解计算机内存
内存是电脑上特别重要的存储器,计算机中所有程序的运行都是在内存中进行的。
所以为了有效的使用内存,就把内存划分为一个个小的内存单元,每个内存单元的大小是1个字节。
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。
编号==地址==指针
如何产生地址?
32位
32根地址线/数据线
一旦通电就有正电和负电之分
1 0
可能性罗列2^32个二进制序列
这些编号又称为对应内存块的编号,又称这个编号是这个内存块的编号地址
指针大小
在32位的机器上一个指针的大小为4字节
在64位的机器上一个指针的大小为8字节
指针里面存地址,地址是32个2进制位或者64个2进制位组成的,换算过来就是4个字节或者8个字节
计算机存储单位
bit、byte、kb、mb、gb、tb、pb、.....
那么每一块空间空间占多少单位呢?0.5gb
用计算器算出1 0000 0000 0000 0000 0000 0000 0000 0000,2进制的1来到第32位,他的权重为2^32,转化为10进制
转化为字节
转化为kb
转换成mb
转化为gb为0.5gb
如果拿一个字节为单位为0.5*8=4g
一个格子为1个字节
#include <stdio.h>
int main(){
int a = 10;//4字节
int* p = &a;//取出a的地址
//有一种变量是用来存放地址的,这种变量被称为指针变量
//在这里int*表示p是一个指向int类型的指针
printf("%p\n",&a);//%p打印地址
printf("%p\n",p);
*p = 20;//解引用操作符,对p进行解引用操作,找到他所指向的对象a
//通过*p找到a里面的值改成20
printf("a = %d\n",a);// 输出修改后的变量a的值,现在应该是20
return 0;
}
举一反三
#include <stdio.h> // 引入标准输入输出库
int main(){
char ch = 'w'; // 定义一个字符变量ch,并初始化为字符'w'
char* Ch = &ch; // 定义一个字符指针变量Ch,并将其初始化为变量ch的地址
*Ch = 'a'; // 通过解引用指针Ch,将变量ch的值修改为字符'a'
printf("%c\n",ch); // 使用%c格式化输出变量ch的值,现在是字符'a'
return 0;
}
结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。
比如描述学生,学生包含:姓名+年龄+性别+学号这几项信息。这里只能用结构体来描述了
#include <stdio.h>
#include <string.h>
struct student{
char name[20];
int age;
char sex[20];
int ID;
};
int main() {
struct student st = {"张三",21,"男",1001};
//操作符. 结构体变量.成员
//操作符-> 结构体指针->成员
printf("姓名:%s\n年龄:%d\n性别:%s\n学号%d\n",st.name,st.age,st.sex,st.ID);
//利用指针打印结果
struct student* stu = &st;
printf("指针打印结果:%s\n",(*stu).name);
//精简写法
printf("精简写法:%s\n",stu->name);
//如果想要修改某一值
st.age = 20;
//由于name是数组名,数组不可改,如果想要修改需要加上strcopy
strcpy(st.name,"李四");//strcopy--string copy--字符串拷贝
//strcpy(目的地,“要拷贝的值”);
//库函数--需要引入头文件#include <string.h>
printf("修改后的年龄为%d\n",st.age);
printf("修改后的姓名为%s\n",st.name);
return 0;
}