一、常量
生活中的有些值是不变的(比如:圆周率,性别,身份证号码,血型等等)
有些值是可变的(比如:年龄,体重,薪资)。
不变的值,C语言中用常量的概念来表示,变的值,C语言中用变量来表示。
C语言的常量分为以下四种:
1.字面常量
3,5.2,10.998等
2.const 修饰的常变量
const指常属性
如const double pi = 3.14;
这个pi就变不了了
若写pi = 5;
就会报错
此时的num还是一个变量,但它具有了常属性。
const int n = 5; int arr[n];
这样在VS2019就不会报错,若去掉const,程序会认为arr[n]中缺少常量表达式。
注:在老版本的编译器里,即使给n加上const修饰,仍然不能通过,这正好证明了n的本质还是一个变量。
3.#define 定义的标识符常量
#define MAX 10
4.枚举常量
可一一列举的量
性别:男,女
三原色:红、黄、蓝
枚举关键字: - enum
enum Sex { MALE, FEMALE, }; int main() { enum Sex s = FEMALE; printf("%d\n%d\n%d\n", s,MALE, FEMALE); return 0; }
打印出来的值分别是1,0,1
枚举常量具有默认值,从0开始
即MALE = 0, FEMALE = 1,这两个量是常量,没法改变
二、字符串、转义字符
1、字符串
“hello\n”
这种由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字 符串。
要输入一个字符串,可以将其放入一个char[]数组中:
char arr1[] = "abc";
printf("%s\n", arr1);
若使用如下代码:
char arr2[] = { 'a','b','c' };
printf("%s\n", arr2);
则打印结果为:
调试-窗口-监视-监视1
会发现arr2字符串中的字符是无效的。
字符串长度为随机值,直到找到了一个'\0'为止。
若使用如下代码:
char arr2[] = { 'a','b','c','\0' };
(把‘0’换成0亦可)
即可正常输出字符串“abc”。
即使固定数组大小,写arr[3] = { 'a','b','c' };
也会输出乱码。
应写:char arr[4] = { 'a','b','c','\0' };
注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容。
数据在计算机上存储的时候,存储的是二进制
ASCII编码:给每个字母对应一个值
a-97
A-65
2、转义字符
转变原来的意思的字符
转义字符 | 释义 |
\? | 在书写连续多个问号时使用,防止他们被解析成三字母词 |
\' | 用于表示字符常量' (如果想要打印一个字符:’,写'''的话,程序会报错,因为系统会将前两个单引号识别为一对,那么它里面是空;所以我们可以将中间那个单引号加上斜杠,使它成为\',这时候它就不再表示括字符的,具有作用的单引号,而是一个常规的字符单引号) |
\" | 用于表示一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符。 |
\a | 警告字符,蜂鸣 |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd表示1~3个八进制的数字。 如: \130 X |
\xdd | dd表示2个十六进制数字。 如: \x30 0 |
例题:printf("%d\n",strlen("c:\test\32\test.c"))
长度是多少?
首先,\t看成一个字符,不是两个;
其次,\32也是一个转义字符,看成一个字符。
32是2个8进制数字
\32作为8进制代表的那个十进制数字,作为ASCII码值,对应的字符
32:2×8^0+3×8^1=26
26作为ASCII码值,代表的字符是→
也就是说,printf("%d\n",'\32');
打印出来的值是:26
printf("%c\n",'\32');
打印出来的值是:→
三、选择语句
int input = 0;
scanf("%d", &input);
if (input == 1)
printf("好offer");
else
printf("卖红薯");
四、循环语句
while
for
do......while
五、函数
#include <stdio.h>
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:>");
scanf("%d %d", &a, &b);
sum = num1 + num2;
printf("sum = %d\n", sum);
return 0;
}
上述代码,写成函数如下:
#include <stdio.h>
int Add(int x, int y)
{
int z = x+y;
return z;
}
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
printf("输入两个操作数:>");
scanf("%d %d", &num1, &num2);
sum = Add(num1, num2);
printf("sum = %d\n", sum);
return 0;
}
函数的特点就是简化代码,代码复用。
六、数组
C语言中给了数组的定义:一组相同类型元素的集合
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
七、操作符
算数操作符
+ - * / %
移二进制位操作符
>> <<
int a = 1;
a:00000000000000000000000000000001
int b =a<<1;
a:00000000000000000000000000000010
左边丢弃,右边补0
即b结果为2,但a没变,仍然是1
二进制位操作符
& 按位与
int a = 3; 011
int b = 5; 101
int c = a&b;
第一位:1与1是1
第二位:1与0是0
第三位:0与1是0
所以结果为:001
那么c的值为1
^ 按位或
第一位:1或1是1
第二位:1或0是1
第三位:0或1是1
所以结果为:111
那么c的值为7
| 按位异或
异或的计算规律:
对应的二进制位相同:0;
对应的二进制位相异:1;
结果为:110
c为6
赋值操作符
=
+=
a = 10;
a = a + 10;//a+10后的值再赋给a
等同于:
a += 10;//给a自己加上一个10
-=
a = a-20;
a -=20;
*=
/=
&=
a = a & 2;
a &= 2;
^=
|=
>>=
<<=
单目操作符(所需操作变量为一个的操作符)
!:逻辑反操作
int a = 10;
printf("%d\n",a);
打印结果为10;
printf("%d\n",!a);
打印结果为0;
因为a不等于10了,所以为假,即0。
-:负值
+:正值
&:取地址
sizeof:操作数的类型长度(以字节为单位,ASCII编码中,一个英文一个字节,一个汉字两个字节)
计算数组大小:
int arr[10] = {0};//10个整型元素的数组
大小为10*sizeof(int) = 40;
也就是这个arr[10]的大小为40字节
~:对一个数的二进制按位取反
int a = 0;
int b = ~a;
a:0000000000000000000000000000
b:11111111111111111111111111111111
b的值输出为-1。
这里涉及到原码,反码,补码。
负数在内存中存储的时候,存储的是二进制的补码。
这里的b是有符号整型,b的二进制最高位是1,代表它是一个负数。
打印的是这个数的原码
原码--符号位不变,其他位取反--反码--加1--补码
补码--减1--反码--符号位不变,其他位取反--原码
b的补码:11111111111111111111111111111111
减1: 11111111111111111111111111111110
取反: 1000000000000000000000000001
得到原码
所以对应十进制数为-1。
--:
++:
1、后置++,a++
int a = 10;
int b = a++;
a = 11,b = 10
先使用a的值,再把a的值自增1;
2、前置++,++a
int a = 10
int b = ++a;
a= =11;b= =11
a先自增1,再使用a的值
*:
间接访问操作符(解引用操作符)
(类型):
强制类型转换
int a = (int)3.14;
把3.14强制转换为int类型
关系操作符
>
>=
<
<=
!=
==
逻辑操作符
&& 逻辑与
int a = 3;
int b = 5;
int c = a&&b;
c=1,为真;
int a = 0;
int b = 5;
此时c = 0,因为a为0,则是假
|| 逻辑或
int c = a||b
a与b只要有1个为真,则为真
条件操作符(三目操作符,具有三个操作数)
exp1?exp2:exp3
expN为表达式
若表达式1为真,则表达式2被执行,且值为整个表达式的结果;
若表达式1为假,则表达式3被执行,且值为整个表达式的结果。
求最大值:
int a = 10;
int b = 20;
int max;
if(a>b)
max = a;
else
max = b;
return 0;
可用条件操作符来表示:
max = (a > b ? a : b);
a>b吗
大于,则max的值为a;
不大于,则max的值为b。
逗号表达式
exp1,exp2,exp3,...expN
下标引用、函数调用和结构成员
[] 下标引用
() 函数调用
. 结构成员
-> 结构成员
八、常见关键字(变量名不能和关键字冲突)
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
1、关键字 typedef
typedef顾名思义是类型定义,这里应该理解为类型重命名。
比如:
//将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名
typedef unsigned int uint_32;
int main()
{
//观察num1和num2,这两个变量的类型是一样的
unsigned int num1 = 0;
uint_32 num2 = 0;
return 0;
}
2、关键字 register
计算机存储数据:
寄存器 空间最小 速度最快
高速缓存 空间较小 速度较快
内存 8G/4G/16G 速度较慢
硬盘 500G 速度最慢
处理数据步骤:内存--拿数据--CPU(中央处理器)
当CPU速度越来越快时,内存还是很慢,跟不上了,所以出现了高速缓存和寄存器
CPU从寄存器里拿即可
若寄存器没有,则拿高速缓存
从上至下依次去拿
register int a = 10;//若a这个数需要被频繁大量使用,则建议将它放入寄存器中
3、关键字 unsigned
无符号关键字
unsigned int a,a为非负数。
4、关键字 static
static是用来修饰变量和函数的
1、修饰局部变量-静态局部变量
//代码1
#include <stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
//代码2
#include <stdio.h>
void test()
{
//static修饰局部变量
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<10; i++)
{
test();
}
return 0;
}
代码1中,在test()函数中的变量i,是一个局部变量,每次调用函数时,都需要重新在这个函数中创建一个i = 0;所以打印出来的值为:1 1 1 1 1 1 1 1 1 1
代码2中,经过static的修饰,变量i变成了一个静态局部变量,改变了它的生命周期,让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束。
2、修饰全局变量-静态全局变量
//代码1
//add.c
int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
//代码2
//add.c
static int g_val = 2018;
//test.c
int main()
{
printf("%d\n", g_val);
return 0;
}
代码1正常,代码2在编译的时候会出现连接性错误。
结论:
一个全局变量被static修饰,使得这个全局变量只能在本源文件内使用, 不能在其他源文件内使用。
3、修饰函数-静态函数
//代码1
//add.c
int Add(int x, int y)
{
return c+y;
}
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
//代码2
//add.c
static int Add(int x, int y)
{
return c+y;
}
//test.c
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
代码1正常,代码2在编译的时候会出现连接性错误。
结论:
一个函数被static修饰,改变了函数的链接属性,将函数的外部链接属性改成了内部链接属性。使得这个函数只能在本源文件内使用,不能在其他源文件内使用。
那么如何引用别的源文件里的函数呢?
使用extern关键字即可:
extern int Add(int,int);
其中Add这个函数是别的源文件下的函数。