1. 变量和基本数据类型
1.1变量类型的概念
变量就是在程序中发生变化的量,变量有类型。
变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。
1字节(byte)=8位(bit)
1.2定义格式
存储类型数据类型变量名;
例如:(auto)inta;
存储类型:变量存储的位置。
数据类型:名字字节取值范围
类型 | 存储大小 | 值范围 | |
char | 字符类型 | 1 字节 | -2^7 到 (2^7-1) |
unsigned char | 无符号字符类型 | 1 字节 | 0 到 (2^8-1) |
int | 整数类型 | 4 字节 | -2^31 到 (2^31-1) |
unsigned int | 无符号整数类型 | 4 字节 | 0 到 (2^32-1) |
short | 短整型 | 2 字节 | -2^15 到 (2^15-1) |
unsigned short | 无符号短整形 | 2 字节 | 0 到 (2^16-1) |
long | 长整型 | 4 字节 | -2^31 到 (2^31-1) |
unsigned long | 无符号长整形 | 4 字节 | 0 到 (2^32-1) |
float | 单精度浮点型 | 4字节 | 有效数据6-7位 |
double | 双精度浮点型 | 8字节 | 有效数据15-16位 |
64位操作系统:long类型是8字节
例子:
1.3初始化格式
(1) 可以定义时初始化
inta=0;
(2) 也可以先定义然后初始化
inta;
a =0;
1.4局部变量和全局变量
(1)生命周期:变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。也就是存活的周期时间。时间维度。
(2)作用域:变量可以起作用的范围。空间维度。
(3)内存大致分配为五个区域:
局部变量、全局变量的区别?(面试题)
局部变量 | 全局变量 | |
1. 定义位置 | 函数体内部 | 函数体外部 |
2. 存储位置 | 栈区 | 全局区 |
3. 生命周期 | 同函数体共存亡 | 同整个程序共存亡 |
4. 作用域 | 作用于函数体内部 | 作用域整个程序 |
5. 初值 | 未初始化,值为随机值 | 未初始化时,值为0 |
当我们在定义变量时,选择正确合适的数据类型,既可以提高空间利用率,同时也可以避免溢出等问题的出现。
未初始化的局部变量为随机值
2. 常量
2.1概念
在程序中不会发生变化的量,存在常量区。
2.2分类
2.2.1字符型常量
类型为char,从ascii表中找的的字符都是字符常量,不可以改变。用单引号括起来的就是字符常量,例如'A'。
类型 | 存储大小 | 值范围 | |
char | 字符类型 | 1 字节 | -128 到 127 |
unsigned char | 无符号字符类型 | 1 字节 | 0 到 255 |
signed char | 带符号字符类型 | 1 字节 | -128 到 127 |
原码、反码和补码:
(1) 最高位表示符号位,正数是0,负数是1。
(2) 正数原码、反码和补码都是一样的。
(3) 负数要用补码来计算:
● 原码就是在数值前面直接加符号表示
● 反码等于原码的符号位不变其余按位取反
● 补码等于反码加一
例如:-5
原码:1000 0101
反码:11111010补码:11111011
补码:
用''括起来的就是字符常量:
'a'字符a
'\0'空字符
' '空格
'\n'换行
例子:
#include <stdio.h>
int main()
{
//可以把字符常量赋值给字符变量
char ch = 'a'; //定义了一个char类型名为ch的变量并赋值为'a'
ch = 'b'; //重新对ch变量赋值为'b'
char ch2 = ch; //定义了一个char类型名为ch2的变量并赋值为了ch的值
printf("%c %c\n", ch, ch2); //分别打印两个变量ch和ch2
printf("%c\n", 'A'); //打印字符'A'
printf("%c\n", 65); //用ASCII值打印'A'
printf("%c\n", '\x41'); //用十六进制的ASCII值打印'A'
printf("%c\n", '\101'); //用八进制的ASCII值打印'A'
return 0;
}
打印结果:
因为C规定转义字符'\x41'中\是转义字符引导符,后跟一个x表示x后面的数字是十六进制表示法,用' '括起来表示一字节ASCII码。\转义符后面加数字代表转义成八进制的字符,后面的数字是八进制。
2.2.2字符串常量
用""括起来的是字符串,'\0'是字符串结尾的标志
"hello"字符串后面有个'\0'
printf("%s \n", "hello world");
2.2.3整型常量
整型就是类型为整数的常量,包括从负数到零到正数的所有整数。可以用二进制、八进制、十进制和十六进制表示。
#include <stdio.h>
int main()
{
int a = 15; //定义了一个数据类型为int的名叫a的变量,并且赋值为常量15
printf("%d\n", 15); //十进制
printf("%d\n", 0b1111); //二进制
printf("%d\n", 017); //八进制
printf("%d\n", 0xF); //十六进制
printf("%d\n", a); //打印保存了15的变量
return 0;
}
打印出来都是15
2.2.4浮点型常量
浮点型常量就是类型为浮点的常量,包括从负数到零到正数所有的浮点数。
floatdouble
2.2.5指数常量
用科学计数法表示
3*10^8-->3e8
2*10^-12-->2e-12
2.2.6标识常量(宏定义)
宏定义:起到标识作用的
(1)只是单纯的进行文本替换,在预处理的时候进行。
(2)遵循标识符的命名规则
(3)一般大写表示
格式:#define宏名常量或表达式
特点:只能单纯替换,不要进行手动运算(原样替换,替换完了再计算)
例子:
练习:
#include <stdio.h>
#define N 2
#define M N + 2
#define SUM N + M / 2 + 1 //2 + 2 + 2 / 2 +1
int main()
{
int a = SUM; //2 + 2 + 2 / 2 +1
printf("%d\n", a); //6
return 0;
}
3. 运算符和表达式
(1) 所谓表达式是指由运算符、运算量和标点符号组成的有效序列,其目的是用来说明一个计算过程。表达式可以独立形成语句,该语句称为表达式语句。
表达式语句的一般形式为:
表达式;
(2) 运算符按功能分为:算数运算符、赋值运算符、关系运算符、逻辑运算符、位运算符和其他运算符
3.1 算术运算符: + - * / % ++ --
(1) /: 整数相除,向下取整
#include <stdio.h>
int main()
{
int a = 3 / 2;
float b = 3 / 2;
float c = 3.0 / 2;
printf("a = %d\n", a); //a = 1
printf("b = %f\n", b); //b = 1.000000
printf("c = %f\n", c); //c = 1.500000
return 0;
}
只针对于常量,不针对于变量
#include <stdio.h>
int main()
{
float a = 3, b = 2;
printf("%f\n", a / b); //1.500000
return 0;
}
(2) %: 只能用于整数运算,取余
10%3 = 1
12%10 = 2
练习:将12345的个十百千万位分别输出到终端。
#include <stdio.h>
int main()
{
printf("%d\n", 12345 % 10);
printf("%d\n", 12345 / 10 % 10);
printf("%d\n", 12345 / 100 % 10);
printf("%d\n", 12345 / 1000 % 10);
printf("%d\n", 12345 / 10000);
return 0;
}
(3) ++: 自增
int a=0;
a++; //相当于 a=a+1;
++a; //相当于 a=a+1;
#include <stdio.h>
int main()
{
int a = 1;
int b = 1;
a++; //a=a+1 ==>a=2
++b; //b=b+1 ==> b=2
printf("%d %d\n", a, b); //2 2
return 0;
}
(4) -- :自减
a--;
--a;
都相当于a=a-1;
和打印语句结合:
printf("%d\n",a++); //++在后,先打印,再自加
//先执行printf("%d\n",a); 再执行a=a+1;
printf("%d\n",++a); //++在前,先自加,再打印
//先执行a=a+1; 再执行printf("%d\n",a);
#include <stdio.h>
int main()
{
int a = 1;
int b = 1;
printf("%d\n",a++); // 1
// 因为相当于先执行printf("%d\n",a); 再执行a=a+1;
printf("%d\n",a); //2
printf("%d\n",++b); //2
//因为相当于先执行b=b+1; printf("%d\n",b);
printf("%d\n",b); //2
return 0;
}
3.2 赋值运算符: = += -+ *= /=
int a=1;
(1) int b = ++a; //先自加然后再赋值
相当于:先执行a=a+1; 再执行 b=a;
(2) int b= a++; //先赋值再自加
相当于: 先执行 b=a; 再执行 a=a+1;
例如:
z = ++x + y++;
相当于:
x=x+1;
z=x+y;
y=y+1;
(3) a+=2;
相当于:a=a+2;
#include <stdio.h>
int main()
{
int a = 1;
a += 2; //a=a+2
printf("%d\n", a); //3
return 0;
}
练习1. 以下程序输出结果是 31
#include <stdio.h>
int main(int argc, char *argv[])
{
int a = 10;
int b = a++; //b=10, a=11
int c = a + b; //c=21 ,b=10,a=11
int d = (b++) +c; //d=10+21=31, b=11
printf("d =%d \n",d);
return 0;
}
2. 以下程序输出结果是 34
#include <stdio.h>
int main(int argc, char *argv[])
{
int a = 10;
int b = ++a; //a=11, b=11
int c = a + (b++); //c = 11+11=22, b=12
int d = b + c; //d=12+22=34
printf("%d\n", d);
return 0;
}
3.3关系运算符:><<=>===!=
用来判断两者的关系,返回1或0。
运算符 | 名称 | 示例 | 功能 | 缩写 |
< | 小于 | a<b | a小于b时返回真,否则返回假。 | LT |
<= | 小于等于 | a<=b | a小于等于b时返回真,否则返回假。 | LE |
> | 大于 | a>b | a大于b时返回真,否则返回假。 | GT |
>= | 大于等于 | a>=b | a大于等于b时返回真,否则返回假。 | GE |
== | 等于 | a==b | a等于b时返回真,否则返回假。 | EQ |
!= | 不等于 | a!=b | a不等于b时返回真,否则返回假。 | NE |
#include <stdio.h>
int main()
{
int a = 2, b = 3;
printf("%d\n", a < b); //1
printf("%d\n", a >= b); //0
printf("%d\n", 100 % 10 != 0); //0
printf("%d\n", 100 % 10 == 0); //1
return 0;
}
3.4逻辑运算符:&& || !
C语言中非0代表真,0代表假
3.4.1&&(逻辑与)
全真则真,一假则假。
全是真的才是真,只要有假就是假。
int a = 2, b = 3;
printf("%d\n", 1 && 1); //1
printf("%d\n", 1 && 0); //0
printf("%d\n", 0 && 1); //0
printf("%d\n", 0 && 0); //0
printf("%d\n", a && b); //1
int x = 100;
printf("%d\n", 2 < x && x < 10); // 判断2<x<10是否满足
3.4.2||(逻辑或)
一真则真,全假则假。
只要有真的就是真,全都是假的才是假。
int a = 2, b = 3;
printf("%d\n", 0 || 0); //0
printf("%d\n", 1 || 0); //1
printf("%d\n", 0 || 1); //1
printf("%d\n", 1 || 1); //1
printf("%d\n", a || b); //1
int x = 100;
//满足x<0或者 x>10
printf("%d\n", x < 0 || x > 10); //1
3.4.3!(逻辑非)
非真为假,非假为真
printf("%d\n", !0); //1
printf("%d\n", !1); //0
printf("%d\n", !(2 < 3)); //0
3.4.4短路法则/截断法则
逻辑或||运算中:如果前面的表达式为真,则后面的表达式不执行。
逻辑与&&运算中:如果前面的表达式为假,则后面的表达式不执行。
例1:
#include <stdio.h>
int main()
{
int a=5,b=6,c=7,d=8,m=2,n=2;
int r=(m=a<b)||(n=c>d); //m=1,n=2,r=1
printf("%d %d %d",m,n,r);
}
用到了短路法则,逻辑或||前面公式判断为真后面不执行,结果为真。
例2:
#include <stdio.h>
int main()
{
int a=5,b=6,c=7,d=8,m=2,n=2;
int r=(m=a>b)&&(n=c>d); //m=0, n=2, r=0
printf("%d %d %d",m,n,r);
}
练习:给出一个年份,判断是平年还是闰年。如果是润年打印1,平年打印0。
(提示:判断闰年还是平年,闰年且闰年二月份以上比平年多一天。普通年份除以4,有余数是平年,对于整百的年份,比如2100年,要除以400,有余数就是平年,整除就是闰年。)
思路,可以设置一个标志flag来接收平年还是闰年。然后用逻辑运算去判断平年还是闰年。最后打印flag。
结果:闰年打印1,平年打印0。
#include <stdio.h>
#define YEAR 1999
int main()
{
int flag = 0;
flag = (YEAR % 100 != 0 && YEAR % 4 == 0) || (YEAR % 400 == 0);
printf("闰年为1,平年为0: %d\n", flag);
return 0;
}
3.5位运算符:&|^~<<>>
含义 | C语言 |
按位与 | a&b |
按位或 | a|b |
按位异或 | a^b |
按位取反 | ~a |
左移 | a<<b |
右移 | a>>b |
无符号右移 | / |
注意:负数都是用补码进行运算的
3.5.1&(位与)
全1则1,有0则0。
例如:
11110101
&11111101
11110101
3.5.2|(位或)
有1则1,全0则0。
例如:
11110101
| 11111101
1111 1101
3.5.3^(异或)
不同为1,相同为0。
例如:
11110101
^ 11111101
00001000
3.5.4~(取反)
按位取反,0变成1,1变成0。
原码 反码 补码
正数:本身本身本身
负数:本身符号位不变其余位按位取反反码+1
~15
正数原码:00001111
正数补码:00001111
取反~:11110000
~-1:
原码:10000001
反码:11111110
补码:11111111
~:00000000
3.5.5<<(左移)
左移几位,右边补几个零。
8<<2 = 32:1000左移两位得到100000
-5<<3:
-5原码:10000101
反码:11111010
补码:11111011
<<3:(111)1101 1000(-40)
10100111(符号位不变,其余按位取反)
10101000 (再上一步基础上+1,得到-40的原码)
3.5.6>>(右移)
右移几位,左边补几个符号位,正数补0负数补1。
8>>2=2
==>0000 0010
-5>>3:
-5原码:10000101
反码:11111010
补码:11111011
>>3: 1111 1111(补码)
10000000
10000001(-1的原码)
3.5.7置一公式和置零公式
置一公式:a | (1<<n)
置零公式:a&(~(1<<n))
3.6特殊运算符
3.6.1三目运算符
表达式:表达式1?表达式2:表达式3
先求解表达式1,如果结果为真(非0)就把表达式2的值作为整个表达式的取值,否则(表达式1结果为假也就是0)那么讲表达式3的值作为整个表达式的结果。
练习:判断以下打印结果
int num1 = 10, num2 = 20;
int res = num1 > num2 ? num1++ : num2++;
printf("num1=%d num2=%d res=%d\n", num1, num2, res);
//10 21 20
2.6.2sizeof()
sizeof运算符运算的格式:
sizeof(数据类型或变量名);
注意:32位系统long是4字节,64位系统是8字节。
3.7 优先级
口诀: 单算移关与 异或逻条赋
从右向左单条赋
练习: 结合宏定义三目运算符实现求两个数的差
#include <stdio.h>
/* 方式1:三目运算符结合宏定义 */
#define M 10
#define N 5
#define DIFF M > N ? M - N : N - M
/*方式2:三目运算符结合宏函数*/
#define DIFF_FUN(a, b) a > b ? a - b : b - a
int main()
{
printf("%d\n", DIFF); //10 > 5 ? 10 - 5 : 5 - 10
printf("%d\n", DIFF_FUN(3, 6)); //调用宏函数
//3 > 6 ? 3 - 6 : 6 - 3
return 0;
}