C语言程序设计第一章

1 C语言浅谈

  1. C语言广泛应用于底层开发。设计目标是提供一种能以简易的方式编译、处理低级处理器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
  2. C语言最初的标准——ANSI C

2 算法浅谈

  1. 算法分为两大类:数值运算和非数值运算
    数值运算的目的是求数值解,如求方程的根、圆的面积、n的阶乘等
    非数值运算的应用十分广泛,主要用于事务管理,如人事管理、图书管理等
  2. 算法的5个特性:
    (1)有穷性。一个算法应当包含有限个操作步骤
    (2)确定性。算法中 每一条指令必须有确定的含义,不能有二义性,对于相同的输入必须能得到相同的输出
    (3)有效性。算法中的每一步都应当有效执行,并得到确定的结果
    (4)有零个或多个输入
    (5)有一个或多个输出
  3. 算法的组成要素包含两大要素:
    (1)操作。每个操作的确定不仅取决于问题的需求,还取决于它们取自哪个操作集,与使用的工具系统有关。计算机算法要由计算机实现,组成它的操作集是计算机所能进行的操作。在高级语言中所描述的操作主要包括各种运算,如算术运算、关系运算、逻辑运算、函数运算、位运算和I/O操作等。计算机算法是由这些操作造成的
    (2)控制结构。即如何控制组成算法的各操作执行的顺序。在结构化程序设计中,一个程序只能由3种基本控制结构组成
    ①顺序结构。顺序结构中的语句是按书写的顺序执行的。
    ②选择结构。最基本的选择结构是当程序执行到某一语句时,要进行判断,从两种途径中选择一条。计算机的判断能力就是通过选择结构来实现的
    ③循环结构。利用循环结构可以将一条或多条语句重复执行若干次。

3 Visual Studio 2019初步使用

  1. 解决方案资源管理器位置:视图
  2. xxxx.c为源文件
  3. xxxx.h为头文件
  4. 运行程序:fn + f5
  5. 调试程序:fn + f10
  6. 监视和内存位置:调试程序后,调试->窗口

4 数据类型

4.1 常量与变量

4.1.1 常量浅谈

其值不能被改变的量成为常量。C语言中,常量有不同的类型,如整型常量(不含小数点)、实型常量(通常用带小数点的数表示)、字符型常量(用单引号括起来的一个字符)、字符串常量(用双引号括起来的若干字符的字符序列)和符号常量(用标识符即符号来表示)等。
C语言中有以下两种方法定义符号常量:

  1. 使用编译预处理命令define。例如,#define PI 3.1415926
  2. 使用常量说明符const。例如,const float PI=3.1415926

4.1.2 变量浅谈

变量是指在程序运行过程中其值可以被改变的量,定义变量的一般形式为:
·        类型名 变量名1,变量名2,…,变量名n;

	int a, b, c;
	char d, e, f;
	long g, h, i;

【注意】C语言中要求所有用到的变量作强制定义,也就是**“先定义,后使用”**,目的如下:
①凡未被事先定义的,系统不把它认作变量名。例如,声明部分有以下语句:int student;
而在执行语句中错写成stadent=30; 在编译时检查出stadent未经定义,不作变量名,因此输出“Undefined symbol ‘stadent’ in function main” (main函数中未定义符号stadent)的信息
②每一个变量被指定为一个确定类型,在编译时就能为其分配相应的存储单元
③指定每一个变量属于一个类型,这就便于在编译时据此检查在程序中要求对该变量进行的运算是否合法

4.2 整型数据

4.2.1 整型常量

整型常量的3中表示形式如下:
①十进制数表示形式:如23、0、-16
②八进制数表示形式:以0开头是八进制数,如023,即八进制数的23(相当于十进制数的19)
③十六进制数表示形式:以0x开头作为十六进制数,如0x23,即十六进制数23(相当于十进制数的25)

4.2.2 整型变量

整型变量的基本类型符为 int 。可以根据数值的范围将变量定义为基本整形、短整型或长整型。因此有以下3种整型变量
①基本整型,以 int 表示。
②短整型,以 short [int] 表示。
③长整型,以 long [int] 表示。
· 若在上述3中类型前再加上无符号整形标记 unsigned,则只能用来存储无符号整数,即在存储单元中的全部二进制位都用来存放数据本身,而没有符号位,也即不能存放负数。于是又有下列3中类型的整型变量
①无符号基本整型,以 unsigned [int] 表示。
②无符号短整型,以 unsigned short [int] 表示。
③无符号长整形,以 unsigned long [int] 表示。
【补充】
①[int] 是可有可无的。
②一个无符号整型变量刚好是其有符号数表示范围的上届与下届绝对值之和
如 signed [int] 可表示 -231-231-1;unsigned [int] 可表示 0~232-1
【注意】
①在一个整型常量后加一个字母u或U,则认为是 unsigned int 型,如123u。
②在一个整型常量后加一个字母l或L,则认为是 long int 型,如0L、123L。

4.3 实型数据

4.3.1 实型常量

在C语言中实型常量又称实数或浮点数,有如下两种表现形式:
(1)十进制形式。它由整数、小数点和小数3部分组成。当整数部分为0或小数部分为0时都可省略,但小数点不能省略。如,3.14、10.8、123..12、0.0等都是十进制数的表示形式,但该种表示形式不适合表示太小或太大的数。
(2)指数形式。它由尾数、大写字母E(或小写字母e)、整数指数3部分组成,适合表示比较小或比较大的数。字符E前必须有数字,且E后的指数必须为整数。如,3.0E+5或3.0e+5都表示3.0×105,1.23E-2表示0.0123。

4.3.2 实型变量

实型变量又称浮点型变量,按能够表示数的精度又分为单精度(float 型)、双精度(double 型)和长精度(long double 型)3种

4.4 字符型数据

4.4.1 字符常量

C语言中把用一对单引号括起来的单个字符称为字符常量。如,‘a’、‘A’、‘1’等。一个字符常量的值是该字符集中对应的编码值,如ASCⅡ字符集中,字符常量’0’-'9’的ASCⅡ编码值是48-57,显然‘0’和数字0是不同的。
C语言中还有一种特殊形式的字符常量,即转义字符常量。转义字符常量以反斜杠 “\” 开头,其后面跟一个特定的字符就转变为另外一种含义。常用的以 “\” 开头的特殊字符如下所示:
①\n------功能:换行,将当前位置移到下一行开头
②\t ------功能:水平制表符(TAB)
③\b------功能:退格,将当前位置移到前一列
④\r ------功能:回车,将当前位置移到本行开头
⑤\f ------功能:换页,将当前位置移到下页开头
⑥\ \ -----功能:代表一个反斜杠字符 “\”
⑦\ '------功能:代表一个单引号字符
⑧\‘’------功能:代表一个双引号字符
⑨\ddd–功能:ddd表示1~3个八进制的数字。如\130–>X
⑩\xdd–功能:dd表示2个十六进制的数字。如\x30–>0
【注意】: d代表要放的数字

int main()
{
	printf("%c\n", '\130');//输出:X(X的ASCⅡ码值是88)
	printf("%c\n", '\101');//输出:A(A的ASCⅡ码值是65)
	printf("%c\n", '\x30');//输出:0(0的ASCⅡ码值是48)
	printf("%d\n", strlen("c:\test\128\test.c"));//14

	return 0;
}

4.4.2 字符变量

字符变量是用来存放字符常量的,并且只能放一个字符,而不是一个字符串。它的关键字类型为 char ,占用1字节的内存单元。例如:
char c1,c2; /定义两个字符变量c1,c2/
c1 = ‘a’; c2 = ‘b’; /给字符变量赋值/
将一个字符常量存储到一个字符变量中,实际上是将该字符的ASCⅡ码值(无符号整数)存储到内存单元中

4.5 字符串常量

(1)字符串常量的定义
字符串常量是用一对双引号括起来的字符序列,即一串字符。字符串中字符的个数称为字符串的长度。长度为0的字符串称为空串,表示为“”。
如果反斜杠和双引号作为字符串的有效字符,则必须使用转义字符
(2)字符串的存储
在存储字符串常量时,由系统在字符串的末尾自动加一个 ‘\0’ 作为字符串的结束标志。如,定义一个char arr[] = “CHINA” 该字符串实际占用内存空间是6个字节,监视内容如下。

-		arr	0x00d6f9e4 "\x1"	char[6]
		[0]	1 '\x1'	char
		[1]	0 '\0'	char
		[2]	0 '\0'	char
		[3]	0 '\0'	char
		[4]	1 '\x1'	char
		[5]	0 '\0'	char

【注意】例:

	char arr1[] = "abc";//当[]内不给初始值系统会默认按照右值进行分配空间
	char arr2[] = {'a', 'b', 'c'};
	//打印字符串
	printf("%s\n", arr1);//输出:abc
	printf("%s\n", arr2);//输出:abc烫烫烫烫蘟bc
  1. 字符串的结束标志是 ‘\0’但在计算字符串长度时不包含 \0
  2. C语言中会自动给字符串后加 ‘\0’
  3. 定义字符数组时需要手动添加 ‘\0’

(3)求字符串长度—— strlen() 函数
使用该函数时需要引用的头文件:

#include <string.h>

函数的使用:

int main()
{
	char arr1[] = "abc";//当[]内不给初始值系统会默认按照右值进行分配空间
	char arr2[] = {'a', 'b', 'c', '\0'};
	char arr3[] = {'a', 'b', 'c',};
	
	//求字符串的长度
	int len = strlen("abcd");//string length
	printf("%d\n", len);//3
	printf("%d\n", strlen(arr1));//3
	printf("%d\n", strlen(arr2));//3
	printf("%d\n", strlen(arr3));//15,随机值,并提示没有结束标志
	return 0;
}

4.6 变量:全局变量和局部变量

#include <stdio.h>

int global = 2022;//全局变量
int main()
{
	int local = 2021;//局部变量
	int gloabl = 2020;//局部变量
	printf("%d\n", gloabl);//结果为2022

	return 0;
}

【结论】:当全局变量和局部变量同名的时候,局部变量优先使用

4.6.1 变量的作用域和生命周期

4.6.1.1 变量的作用域

引例:

#include <stdio.h>

int main()
{
	int a = 10;
	printf("%d\n", a);//a可用

	return 0;
}

【成功运行】

#include <stdio.h>

int main()
{
	{
		int a = 10;
	}
	printf("%d\n", a);//a不可用

	return 0;
}

【错误警告】:“a”:未声明的标识符

#include <stdio.h>

int g_val = 2022;//全局变量
int main()
{
	printf("1:%d\n", g_val);//可用
	{
		printf("2:%d\n", g_val);//可用
		int a = 10;
		printf("%d\n", a);//a不可用
	}
	printf("3:%d\n", g_val);//可用
	
	return 0;
}

【成功运行】
【结论】

  1. 局部变量的作用域:就是变量所在的局部范围
  2. 全局变量的作用域:整个工程
4.6.1.2 变量的生命周期

一个变量的生命周期:变量的创建和销毁之间的时间段
引例:

int main()
{
	{
		int a = 10;//局部变量
		printf("%d\n", a);
	}
	//进入局部范围生命开始,出局部范围生命结束
	printf("%d\n", a);

	return 0;
}

【结论】

  1. 局部变量的生命周期:进入局部范围生命开始,出局部范围生命结束
  2. 全局变量的生命周期:程序的生命周期

4.7 常量

  1. 字面常量
    例:
	3.14;
	10;
	'a';
	"avswv";
  1. const 修饰的常变量
    即需要某一变量其值不再改变,可在前加修饰符 const 固定其值
const int num = 10;//num就是常变量-具有常属性,即不能被改变的属性

【结论】被const修饰的变量,虽然具有常属性,但本质上仍然是变量

  1. #define 定义的标识符常量
#define MAXSIZE 10000
int main()
{
	//MAXSIZE = 200;//error
	int n = MAXSIZE;
	printf("n = %d\n", n);//输出:10000

	return 0;
}

【结论】 被 #define 定义的常量是不可被修改的。#define可也在括号内定义

  1. 枚举常量
    即可以一一列举的常量,如性别,三原色等常识类常量
enum Sex
{
	//这种枚举类型的变量的未来可能取值
	MELE = 3,//赋初值
	FEMALE,
	SECRET,
};//枚举常量
int main()
{
	//MELE = 7;//error
	enum Sex s = MELE;
	printf("%d\n", MELE);//输出:3
	printf("%d\n", FEMALE);//输出:4
	printf("%d\n", SECRET);//输出:5

	return 0;
}

【结论】枚举常量的定义类似于结构体的定义,和 enum 固定搭配使用。声明一个枚举常量后,不可再修改。

5 运算符与表达式

· 运算符是表示某种操作的符号,在C语言中,除控制语句和输入/输出函数外,其他所有基本操作都作为运算符处理。运算符的操作对象称为运算数,用运算符把运算数链连接起来的一个有意义的式子就叫做表达式
C语言运算符可以分为以下几类:

  1. 算术运算符:+ - * / % ++ - -
  2. 关系运算符:> >= < <= == !=
  3. 逻辑运算符:&& || !
  4. 赋值运算符:= += -= *= /= %= &= |= ^= <<= >>=
  5. 条件运算符:? :
  6. 逗号运算符:,
  7. 位运算符: & | ^ ~ << >>
  8. 指针运算符:* &
  9. 求字节数运算符:sizeof
  10. 强制类型转换运算符 :(类型标识符)
  11. 分量运算符:. ->
  12. 下标引用运算符:[ ]
  13. 圆括号(函数调用运算符):( )

5.1 算术运算符与算术表达式

5.1.1 基本的算术运算符

  1. +:加法运算符或取正值运算符,如1 + 2、+2
  2. -:减法运算符或负值运算符,如2 - 1、-2
  3. *:乘法运算符,如1 * 2
  4. /:除法运算符,如5/2
  5. %:求余运算符,或称模运算符,如7 % 5的值为2

【注意】:如果操作数中有负数,则取整通常采用“向零取整”的方法。如5/-3 = -1

5.1.2 算术表达式和运算符的优先级与结合性

  1. 优先级
    如先乘除后加减,例如 a + b * c 相当于 a + (b * c)
  2. 结合性
    如果一个运算对象两侧的运算符的优先级别相同,如 a - b + c ,则按规定的结合方向(结合性)处理。
    算术运算符的结合方向为自左至右,也称其有左结合性。有些问题如赋值表达式和复合赋值运算符则包含右结合性。

5.1.3 自增、自减运算符

  1. ++:表示使单个变量的值加1的运算符,称为自增运算符
  2. - -: 表示使单个变量的值减1的运算符,成为自减运算符

自增、自减运算符的两种用法:

  1. 前置运算(先自增、自减,后运算)
    如,j = ++i,其中i = 2,先计算 i = i + 1 = 3,后赋值 j = 3,结果是 i = 3, j = 3
  2. 后置运算(先运算,后自增、自减)
    如,j = i++,其中i = 2, 先赋值 j = 2,后自增 i = i + 1 = 3,结果是 i = 3, j = 2
    【注意】后置运算是将所有的运算都结束后再自增、自减
int main()
{
	int i = 2;
	printf("i=%d\n", i);//i=2
	int j;
	j = ++i;
	printf("i=%d j=%d\n",i,j);//i=3 j=3
	j = i--;
	printf("i=%d j=%d\n",i,j);//i=2 j=3

	return 0;
}
int main()
{
	int x = 11;
	int sum = (x++ * 1 / 3);
	printf("%d,%d\n", x,sum);//12,3,所有运算都结束后再自增

	return 0;

【注意】

  1. 自增、自减运算符只能用于变量,不能用于常量和表达式
  2. 自增、自减运算符常用于循环语句中,使循环控制变量加(减1),还用于指针变量中,使指针指向下(或上)一个地址
  3. 当自增、自减运算与其他运算混合时,前置和后置形式影响不同

5.2 赋值运算符和赋值表达式

5.2.1 赋值运算符

C语言中赋值符号是“=”,它的作用是将赋值运算符右边表达式的值赋给左边的变量

int main()
{
	int a = 5;
	int x = (a + 3) / 5;
	printf("a=%d, x=%d\n",a,x);//a=5, x=1

	return 0;
}

【注意】如果“=”两侧的类型不一致,则在赋值时要进行类型转换。

5.2.2 复合赋值运算符

在赋值运算符“=”之前加上一个其他运算符,可以构成复合赋值运算符。C语言规定了如下10种复合赋值运算符(右结合性):+= -= *= /= %= &= |= ^= <<= >>=

  1. +=:加赋值,如,a+=b 等价于 a = a+b
  2. -=:减赋值,如,a-=b 等价于 a = a-b
  3. *=:减赋值,如,a*=b 等价于 a = a*b
  4. /=:减赋值,如,a/=b 等价于 a = a/b
  5. %=:减赋值,如,a%=b 等价于 a = a%b

5.2.3 赋值表达式

  1. 赋值表达式
    赋值表达式的功能是将赋值运算符右边“表达式”的值赋给左边的变量,赋值表达式一般格式如下:
    <变量> <赋值运算符> <表达式>
    【注意】赋值表达式左边必须是变量
  2. 赋值表达式的值
    如,设 a = 5,“a+=a-=a*a”,求a的值
    根据右结合性,原式等价于“a+=a=a-a*a”,先计算“a=a-a*a”,a = 5-5*5 = -20,再计算“a += a”,a=-40

5.3 关系运算符和关系表达式

5.3.1 关系运算符

C语言提供6种关系运算符:
>(大于) >=(大于等于) <(小于) <=(小于等于) ==(等于) !=(不等于)
在这6种关系运算符种,前4种关系运算符的优先级相同,后2种关系运算符的优先级相同,且前4种关系运算符的优先级高于后2种关系运算符的优先级。与其他运算符的优先级相比,关系运算符的优先级低于算术运算符,但高于赋值运算符
例如:

//c>a+b 等价于 c>(a+b)		算术运算符
//a==b>c 等价于 a==(b>c)		关系运算符
//a=b>c 等价于 a=(b>c)		赋值运算符

优先级:算术运算符>关系运算符>赋值运算符

5.3.2 关系表达式

  1. 关系表达式
    由关系运算符将两个表达式(可以是算术表达式或关系表达式、逻辑表达式、赋值表达式、字符表达式)连接起来的式子称为关系表达式
    例如:
    a>b, a+b>c-d, (a=3)<=(b=5), ‘a’>=‘b’, (a>b)==(b>c)
    以上都是合法的
  2. 关系表达式的值
    关系表达式的值是一个逻辑值,即“真”或“假”。由于C语言没有逻辑型数据,C语言中1代表“真”,0代表“假”
int main()
{
	int n1 = 3, n2 = 4, n3 = 5;
	printf("%d\n", n1 > n2);//0
	printf("%d\n",(n1 > n2) != n3);//1
	printf("%d\n", n1 < n2 < n3);//1
	printf("%d\n", (n1 < n2) + n3);//6

	return 0;
}

5.4 逻辑运算符和逻辑表达式

关系表达式只能描述单一条件,如“x>=0”。如果需要描述“x>=0”同时“x<10”,就需要借助逻辑表达式

5.4.1 逻辑运算符

  1. 逻辑运算符
    C语言提供3种逻辑运算符:&&(逻辑与=‘同时’) ||(逻辑或=‘或者’) !(逻辑非=‘否定’)
  2. 逻辑运算符的运算规则
    &&:当且仅当两个运算量的值都为“真”时,运算结果为“真”,否则为“假”。“一假则假”
    ||:当且仅当两个运算量的值都为“假”时,运算结果为“假”,否则为“真”。“一真则真”
    !:当运算量的值为“真”时,运算结果为“假”,反之亦反
  3. 逻辑运算符的优先级
    (1) !(逻辑非) > &&(逻辑与’) > ||(逻辑或)
    (2)与其他运算符的优先级相比,其优先级由高到低次序如下所示
    !(逻辑非) > 算术运算符 > 关系运算符 > &&(逻辑与’) > ||(逻辑或) > 赋值运算符
    例:
int main()
{
	int a = 2, b;
	printf("%d\n", b=a==!a);//先算!a值为0,再算a==a值为0,最后算b=a值为0

	return 0;
}

5.4.2 逻辑表达式

  1. 逻辑表达式
    即将一个或多个表达式连接起来,进行逻辑运算的表达式
    例如:(a>b)&&(x>y)||(a<=b)
    逻辑表达式的值也是一个逻辑值(非“真”即“假”)
  2. 逻辑量的真假判定——0或非0
    在判断一个数据的“真”或“假”时,以0和非0为根据:如果为0,则判定为“假”;如果为非0,则判定为“真”
    例如:设 num = 12,则 !num 的值为0,num>=1&&num<=31 的值为1,num||num>31 的值为1
    【注意】
    (1)逻辑运算符两侧的操作数,可以是0和非0的整数,也可以是其他任何类型的数据,如实型、字符型等
    (2)在计算逻辑表达式时,并不是所有的逻辑运算符都被执行,只有在必须执行下一个逻辑运算符才能求出表达式的解时,才执行该运算符。
    ①对于逻辑与运算,如果第一个操作数被判定为“假”,则系统不再判定或求解第二个操作数
    例如:
int main()
{
	int m = 1, n = 1, a = 1, b = 2, c = 3, d = 4;
	printf("%d\n", (m=a>b)&&(n=c>d));//0
	printf("%d\n", m);//0
	printf("%d\n", n);//1,对于逻辑与运算,如果第一个操作数被判定为“假”,则系统不再判定或求解第二个操作数

	return 0;
}

②对于逻辑或运算,如果第一个操作数被判定为“真”,则系统不再判定或求解第二个操作数
例如:

int main()
{
	int m = 0, n = 0, a = 1, b = 2, c = 3, d = 4;
	printf("%d\n", (m = b > a) || (n = d > c));//1
	printf("%d\n", m);//1
	printf("%d\n", n);//0,对于逻辑或运算,如果第一个操作数被判定为“真”,则系统不再判定或求解第二个操作数

	return 0;
}

5.5 逗号运算符和逗号表达式

5.5.1 逗号运算符

逗号运算符的优先级时C语言种所有运算符中最低的,结合方向为左结合

5.5.2 逗号表达式

逗号表达式是由一系列逗号将表达式连接起来的式子,其一般形式如下:
表达式1, 表达式2, ···, 表达式n
逗号表达式的求解过程:由逗号隔开的一对表达式从自左至自右依次计算各表达式的值,“表达式n”的值即为整个逗号表达式的值
例如:

int main()
{
	int a;
	printf("%d\n", (a = 2 + 3, a = a * 6, a / 10));//3, “表达式n”的值即为整个逗号表达式的值

	return 0;
}

5.6 位运算符

C语言提供了以下6种位运算:

  1. “按位与”运算符(&)
    格式:x&y
    规则:参与运算的两数对应的二进位相与,只有对应的两个二进位均为1时,结果位才为1,否则为0
    例如:3&9 = 1
               0011
         (&) 1001  
             0001
  2. “按位或”运算符(|)
    格式:x|y
    规则:参与运算的两数对应的二进制相或,只要对应的两个二进位有一个为1时,结果位就为1
    例如:3|9 = 11
               0011
          (|)  1001  
             1011
  3. “异或”运算符(^)
    格式:x^y
    规则:参与运算的两数对应的二进位相异或,当两个对应的二进位相异时结果位就为1,相同时结果位就位0
    例如:3^9 = 10
               0011
         (^)  1001  
             1010
  4. “取反”运算符(~)
    格式:~x
    规则:参与运算的数的各个二进位按位求反,即将0变1,将1变0。(包括符号位)
    例如:~14 = 1
               1110
         (~)        
             0001
  5. “左移”运算符(<<)
    格式:x<<位数
    规则:把“<<”左边的运算数的各二进位全部左移若干位,由“<<”右边的数指定移动的位数,高位丢弃,低位补0
    例如:5<<2 = 20
               00000101
         (<<2)       
             00010100
  6. “右移”运算符(>>)
    格式:x>>位数
    规则:把“>>”左边的运算数的各二进位全部右移若干位,由“>>”右边的数指定移动的位数。应该注意符号位的问题,对无符号数,右移时左边高位移入0;对于有符号数,右移时符号位将随同移动。当为正数时,最高位补0;为负数且符号位为1时,最高位是补0还是补1取决于编译系统的规定
    例如:20>>2 = 5
               00010100
         (>>2)       
             00000101
    除按位取反运算外,其余5个运算符均可与赋值运算符一起构成复合赋值运算符,如 &=、|=、^=、<<=、>>=
    例如:a&=b 相当于 a = a&b

【补充】

  1. 整数在内存中存储的是补码
  2. 一个整数的二进制表示有3种:
    (1)原码
    (2)反码
    (3)补码
  3. 一个负数的原码、反码、补码的计算方式:
    (1)原码:最高位为符号位,其他位为数据位
    (2)反码:符号位不变,其他位取反
    (3)补码:反码的二进制位+1就是补码
    如:-1
    10000000000000000000000000000001(原码)
    1111111111111111111111111111111111110(反码)
    1111111111111111111111111111111111111(补码)
  4. 一个正数的原码、反码、补码相同
    例如:~0 = -1 用二进制位应该如何表示?
    分析:
    ~0的二进制位为(补码形式):1111111111111111111111111111111111111
    ( 由于最高位的符号位为1,即为负数,为了找回原码,应先计算其反码)
    ~0的反码形式(补码-1): 1111111111111111111111111111111111110
    ( 再推其原码:最高位的符号位不变,其他位按位取反)
    ~9的原码形式:10000000000000000000000000000001
     
    例如:~9 = -10 用二进制位应该如何表示?
    分析:
    9的二进制位为(补码形式):00000000000000000000000000001001
    ~9的二进制位为(补码形式):1111111111111111111111111111111110110
    ~9的反码形式(补码-1):1111111111111111111111111111111110101
    ~9的原码形式(对反码按位取反,且符号位不变):10000000000000000000000000001010(-10)
int main()
{
	int a = 0;
	printf("%d\n", ~a);//-2

	return 0;
}

5.7 求字节数运算符

sizeof() 是一个运算符,用于计算类型或变量的大小,也可计算数组大小
例:

int main()
{
	long long a = 100;
	printf("%d\n", sizeof(int));//4
	printf("%d\n", sizeof(a));//8
	
	return 0;
}

【注意】使用sizeof运算符时,计算函数大小时不能省略后面的 () ,只有当计算变量大小时可省略后面的 () 。规范写法通常都不省略

int main()
{
	long long a = 100;
	printf("%d\n", sizeof (int));//4,计算函数大小时不可省略括号
	printf("%d\n", sizeof a);//8,计算变量大小时可省略括号
	
	return 0;

【补充】可利用 sizeof() 运算符计算数组元素个数,公式:sizeof(arr)/sizeof(arr[0])

int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz);//C语言中是用该方法计算数组元素个数的

	return 0;
}

5.8 条件运算符

公式:exp1 ? exp2 : exp3
规则:

  1. 当表达式1(exp1)成立时,执行表达式2(exp2)的计算,整个表达式的结构是:表达式2(exp2)的结果;
  2. 当表达式1(exp1)不成立,执行表达式3(exp3)的计算,整个表达式的结构式:表达式3(exp3)的结果
int main()
{
	int a = 0;
	int b = 3;
	int max = 0;

	max = a > b ? a : b;

	printf("%d\n", max);//3
	return 0;
}

5.9 下标引用运算符

[ ]:用于下标引用
例:

int main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	printf("%d\n", arr[6]);//6,[]下标引用运算符

	return 0;
}

5.10 圆括号(函数调用运算符)

调用函数是,函数名后边的 () 就是函数调用运算符
例如:

int main()
{
	//调用函数是,函数名后边的 () 就是函数调用运算符
 	printf("hehe\n");
	printf("%d\n", 100);

	return 0;
}

6 数据类型转换

6.1 自动类型转换

C语言允许在整形、实型、字符型等数据之间进行混合运算,在进行运算时,首先将不同类型的数据转换成同一类型,然后进行运算
例如:

  1. 字符型(char)和短整型(short)必定要先转换成整型(int)
  2. 单精度型(float)必定要先转换成双精度型(double)
  3. 赋值号右边的类型转换为赋值号左边的类型,结果为赋值号左边的类型

数据类型转换关系:
①即使在同一种数据类型之间进行运算时,也要进行转换:
char——>short——>int
float——>double
②当运算对象类型不同时的转换
int——>unsigned——>long——>double
【注意】若int型和double型混合运算,不是int型先转为unsigned型,再转为long型,最后再转为double型,而是直接转为double型

6.2 强制类型转换

可以利用强制类型转换运算符将一个表达式转换成所需类型。强制类型转换的一般格式如下:
(类型名)(表达式)
例如:

(double)a(等价于(double)(a)) //将变量a的值转换成double类型
(int)(x+y) //将x+y的结果转换成int型
(float)5/2(等价于(float)(5)/2) //将5转换成实型,再除以2(结果为2.5)
(float)(5/2) //将5整除2的结果(2)转换成实型(2.0)
int main()
{
	float a = (float)5 / 2;
	printf("%f\n", a);//2.5

	float b = (float)(5/2);
	printf("%f\n", b);//2.0
	return 0;
}

【注意】在强制类型转换是,得到的是一个所需类型的中间量,原来变量的类型并不发生变化。如(double)a,只是将变量a的值转换成一个double型的中间量,a的数据类型并未转换成double型

7 指针浅谈

7.1 内存浅谈

  • 计算机中所有程序的运行都是在内存中进行的。所以为了有效的使用内存,就把内存划分为一个个晓得内存单元,每个内存单元的大小是1个字节。为了能够有效地访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址

7.2 取地址运算符 & 和指针变量的定义

  • 当存储地址时,需要定义指针变量,需要用到取地址运算符 &
int main()
{
	int a = 10;//a在内存中要分配空间 - 4个字节
	printf("%p\n", &a);//00AFF930 (%p - 专门用打印地址的)
	int* pa = &a;//pa是用来存放地址的,在C语言中pa叫指针变量
	printf("%p\n", pa);//00AFF930

	// * 说明:pa是指针变量
	// int 说明:pa指向的对象是int类型的

	char ch = 'w';
	char* pc = &ch;
	printf("%p\n", pc);//012FF9EF
	
	return 0;
}

【注意】%p - 专门用打印地址的

7.3 解引用操作 *

  • * 解引用操作,通过指针变量里的地址,找到所指向的变量,后续可对其进行其他操作
int main()
{
	int a = 10;
	int* pa = &a;

	*pa = 20;//这里的 * 叫解引用操作, *pa 就是通过pa里边的地址,找到a

	printf("%d\n", a);

	return 0;
}

7.4 指针的大小

  • 所有类型的指针大小都是相同的,都是4个字节。因为指针是用来存放地址的,指针需要多大空间,取决于地址的存储需要多大的空间(在32位机器上,32 bit = 4 byte;在64位机器上,64 bit = 8 byte)
int main()
{
	printf("%d\n", sizeof(char *));//4
	printf("%d\n", sizeof(short *));//4
	printf("%d\n", sizeof(int *));//4
	printf("%d\n", sizeof(long *));//4
	printf("%d\n", sizeof(long long *));//4
	printf("%d\n", sizeof(float *));//4
	printf("%d\n", sizeof(double *));//4

	return 0;
}

8 结构体浅谈

  • 结构体使得C语言有能力描述复杂类型

8.1 分量运算符

(1). 运算符的用法:结构体的变量 . 成员变量
(2)-> 运算符的用法:结构体的指针 -> 成员变量
(3)*结构体指针变量 等价于 结构体的变量(*解引用操作)

//创建一个学生类型
struct Stu
{
	char name[20];//成员变量
	int age;
	double score;
};

int main()
{
	//结构体的创建和初始化
	struct Stu s = { "张三", 20, 85.5 };
	printf("1: %s %d %lf\n", s.name, s.age, s.score);// . 运算符 - (结构体变量 . 成员变量)
	struct Stu * ps = &s;//结构体指针变量
	printf("2: %s %d %lf\n", (*ps).name, (*ps).age, (*ps).score);//等价于1的写法

	//最直观的写法:结构体的指针->成员变量
	printf("3: %s %d %lf\n", ps->name, ps->age, ps->score);//等价于2的写法

	return 0;
}

C语言补充知识

  1. 使用已有的库函数,需要“打招呼”——即引用头文件,如使用 printf ()函数需要头文件 stdio.h
    需要引用的头文件:
#include <stdio.h>
  1. 一个工程中可以有多个.c文件,但是多个.c文件中只能有一个main函数
  2. 打印十进制数用%d;打印unsigned整数用%u;打印float用%f;打印double用%lf;打印char用%c;打印字符串用%s
  3. 当使用scanf函数时若出现以下该错误:
    /错误 C4996 ‘scanf’: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details./
    (这个函数或变量不安全,建议使用scanf_s代替,可使用_CRT_SECURE_NO_WARNINGS去屏蔽)
    需要在代码第一行添加
#define _CRT_SECURE_NO_WARNINGS 1
  1. 若要使用同一工程下其他.c源文件的全局变量,只需声明改变量即可
    例如:
extern int g_val;
  1. 若要使用同一工程下其他.c源文件的函数,只需声明改变量即可
extern int Add(int x, int y);
  1. C语言提供的关键字:
    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 unsigned union void volatile while
    auto:是自动的——每个局部变量都是auto修饰的,基本上都是省略掉的,新的C语言语法中也有其他用法
    const:修饰常变量
    enum:枚举常量的关键字
    extern:是用来申明外部符号的
    register:寄存器关键字
    static:静态的
    struct:结构体关键字
    typedef:类型重定义
    union:联合体(共用体)
    void:无、空
typedef unsigned int u_int;//typedef 类型重定义
int main()
{
	unsigned int num1 = 100;
	u_int num2 = 100;

	return 0;
}

static - 静态的

  1. static修饰局部变量
  2. static修饰全局变量
  3. static修饰函数

(1)static修饰局部变量,改变了局部变量的生命周期(本质上是改变了变量的存储类型)

栈区堆区静态区
局部变量动态内存分配的全局变量
函数的参数static修饰的静态变量
void test()
{
	static int a = 1;
	a++;
	printf("%d ", a);
}

int main()
{
	int i = 0;
	while (i < 10)
	{
		test();//2 3 4 5 6 7 8 9 10 11
		i++;
	}

	return 0;
}

(2)static修饰全局变量,使得全局变量只能在自己所在的源文件(.c文件)内部可以使用,其他源文件不能使用:
全局变量在其他源文件内部可以使用,是因为全局变量具有外部链接属性。但是被static修饰之后,就变成了内部链接属性,其他源文件就不能链接到这个静态的全局变量
在这里插入图片描述

(3)static修饰函数,使得函数只能在自己所在的源文件(.c)内部可以使用,其他源文件不能使用
【注意】本质上:static是将函数的外部链接属性变成了内部链接属性!(和static修饰全局变量一样)
在这里插入图片描述
在这里插入图片描述
#define定义常量和宏
(1)#define定义常量

//define 是一个预处理指令
//1.define定义符号
#define MAX 1000
int main()
{
	printf("%d\n", MAX);
	
	return 0;
}

(2)#define定义宏
格式:#define Add(x, y) ((x)+(y))

//2.define定义宏
#define Add(X,Y) ((X)+(Y))//需要给每个表达式加括号,保证其计算的优先级
int main()
{
	printf("%d\n", 4*Add(2,3));//20

	return 0;
}

【注意】#define定义宏时,x和y可能是变量,也可能是表达式,所以需要加括号,保证其自己单独作为一个整体
【注意】

  1. 不能自己创建关键字
  2. 变量名不能是关键字
  3. define和include不是关键字,是预处理指令
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值