数据类型

字符数据类型

类型 写法 大小
字符数据类型 char 1
短整型 short 2
整形 int 4
浮点型(单精度) float 4
长整型 long 4
更长整型 long long 8
双精度 double 8

赋值

1
2
3
4
5
6
7
8
9
10
int main()v
{
int age = 18;
char *name = "caixukun";
short num = 20;
float weight = 55.5;
double d = 6.66;
printf("%d\n", 100);//打印整数 -%d
return 0;
}
1
sizeof()//算大小,单位是字节byte

计算机单位

  • bit - 比特
  • byte - 字节 = 8字节
  • kb - 1024 byte
  • mb
  • gb
  • tb
  • pb

常量与变量

变量

1
type vname = value; 
写法 含义 备注
%d 整数
%f 浮点数
%lf 双精度
%c 打印字符 配合printf可以用ASCII码打印对应字符
%s 打印字符串

分类

  • 全局变量
    {} 外部定义的
  • 局部变量
    {} 内部定义的

优先级

出现同名时,==局部变量优先==

1
2
3
4
5
6
7
8
9
#include <stdio.h>
int num = 10;

int main()
{
int num = 1;
printf("%d\n", num);//结果是1
return 0;
}

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define _CRT_SECURE_NO_WARNINGS 1
//放在代码第一行,取消scanf报错显示
#include <stdio.h>
//头文件

int main()
{
int a = 0;
int b = 0;
int sum = 0;

printf("请输入两个数字");
scanf("%d %d", &a, &b);//&取地址
//scanf是vs提供的,只能在vs里写,不是C语言标准
//scanf()是输入函数
sum = a + b;
printf("sum= %d\n", sum);
return 0;
}

作用域

变量的适用范围

  • 局部变量
    ==局部范围==,例如大括号内

  • 全局变量
    整个工程

1
2
3
4
5
6
7
8
extern int v_gal = 1;//声明变量

int main()
{
printf("%d\n", v_gal);

return 0;
}

生命周期

变量的生命周期是指变量创建销毁的时间段

局部变量的生命周期是{}内

全局变量是整个程序内


常量

字面常量

const修饰的常变量

1
2
const int mum =10;
//num是const修饰的常变量-具有常属性
1
2
3
4
5
6
7
8
9
10
# include<stdio.h>
int main()
{
int arr[10] = {0};//10个元素

int n = 10;
const int arr2[n] = {0};//n是变量,这里需要在int前加const修饰为常变量

return 0;
}

define定义的标识符常量

1
2
3
4
5
6
7
8
9
#define MAX 10000;
//define定义的标识符常量

int main()
{
int n = MAX;
printf("n = %d\n", n);
return 0;
}

枚举常量

可以 一一列举 的常量,值是0,1,2…(默认从0开始)
例如:男女、三原色、星期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//性别
enum Sex
{
//这种枚举类型的变量的未来可能取值
//枚举常量
MALE,
FEMALE,
SECRET,
};

int main()
{
enum Sex s = MALE;
//s是创建的一个变量
//不输以上三种之一会报错
printf("%d\n",MALE);
printf("%d\n",FEMALE);
printf("%d\n",SECRET);
//会输出0,1,2
return 0;
}


字符串

是用双括号引起的一串字符

结束标志是\0(诡计多端的0)
结束标志不算在长度中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <string.h>//strlen函数的头文件

int main()
{
//字符数组
char arr[] = "hello";
char arr1[] = "abc";
char arr2[] = {'a', 'b', 'c'};

printf("%s\n", arr1);
printf("%s\n", arr2);//会乱码,因为arr2最后面没有结束标志"\0"

int len = strlen("abc");//strlen看字符串长度,要引用头文件
printf("%d\n",len);//可看出最后的"\0"不算在长度中

printf("%d\n", strlen(arr1));//结果为3
printf("%d\n", strlen(arr2));//结果为随机数,因为"arr2"后没有结束标志

return 0;
}

转义字符

转变了原来的意思

1
2
3
4
5
int main()
{
printf("ab\c");//打印不出"c"
return 0;
}
转义字符 释义 例子
? 书写多个问号时使用,防止被解析为三字母词 比如??)会被解析为]
用于表示字符常量 输出普通的单引号’
" 用于表示一个字符串内部的双引号 一个原理
|用于表示反斜杠 一个原理
\a 警告字符,蜂鸣 让电脑响一下
\b 退格符
\f 进纸符
\n 换行
\r 回车
\t 水平制表符 等同于按tab
\v 垂直制表符
\ddd ddd表示1~3个八进制数字 如:\130 X
\xdd dd表示2个十六进制数字 如:\x30 0
1
2
3
4
5
6
int main()
{
printf("%c\n",'\130');//八进制数字,在十进制中是88,88是X的ASCII码,会输出X
printf("%d\n", strlen("\328"));//显示2,因为8超出八进制范围
return 0;
}

注释

用于解释复杂代码

注释方法有两种

  • C++注释方法
    • //以此为始
    • 不支持嵌套注释
  • C注释法
    • 分别在上下两行,以/*为始,以*/为终
    • 支持嵌套注释

选择语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define _CRT_SECURE_NO_WARNINGS 1//防止scanf报错

int main()
{
int input = 0;//输入的值
printf("卢本伟牛逼逼\n");
printf("要开挂吗(0/1)?");
scanf("%d", &input);

if (input == 1)
{
printf("我没有开挂\n");
}
else
{
printf("开挂死全家\n");
}
return 0;
}

循环语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
int line = 0;
while(line<30000)
{
printf("写代码:%d\n", line);
line++;//累加器,起到计数的作用
}

if (line == 30000)
{
printf("您已成功飞升\n");
}
return 0;
}

函数

引用函数就是在套娃使用,自定义函数也是这个原理,利用函数可以方便实现各种功能的快速使用

1
2
3
4
5
6
7
8
int main()
{
int num1 = 0;
int num2 = 0;
scanf("%d%d", &num1, &num2);//&是取地址,把输入的丢进去目的地里
int sum = num1 + num2;//可以理解sum在系统中和下面自定义的Add一样已经定义过,在这里直接引用
return 0;
}

和以下代码等价

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int Add(int x, int y)
//相当于自定义了一个Add函数,由于输入的是数值,输出的也是数值所以加了int在Add前
{
int z = 0;
z = x + y;
return z;//把z的值返回给Add
}

int main()
{
int num1 = 0;
int num2 = 0;
scanf("%d%d", &num1, &num2);
int sum = Add(num1,num2);
return 0;
}

数组

存储一组相同类型的元素的集合

1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
int i = 0;
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
//给数组赋值,可以不必对每个元素赋值,也就是不完全初始化,默认为0
//元素下标从0开始
while (i < 10)
{
printf("%d ", arr[i]);
i++;
}
return 0;
}

操作符

算术操作符

  • +加法
  • -减法
  • 乘法
  • 除法
1
2
3
4
5
6
7
//除法的运算和数的类型有相当大的关系
int main()
{
int a = 9 / 2;//结果是2
float b = 9 / 2.0;//结果是4.5
return 0;
}
  • %取模

移位操作符

移动的是二进制位
向左移动一位就是变成222^2

  • >> 向右
  • <<向左移一位

位操作符

  • &按位与
  • \按位或
  • ^按位异或

赋值操作符

符号 含义 备注
=
+=
-=
*=
/=
&=
^=
|=
>>=
<<=
1
2
3
4
5
6
7
int main()
{
a = a + 5;
a +=5;
//以上两者等价
return 0;
}

单目操作符

符号 含义 备注
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
前置、后置– 前置先加加再使用,后置先使用再加加
++ 前置、后置++
* 间接访问操作符(解引用操作符)
() 强制类型转换
1
2
3
4
5
6
int main()
{
int a = (int)3.14;//强制从double转换成int
printf("%d\n", a);
return 0;
}

逻辑操作符

符号 含义
&& 逻辑与
|| 逻辑或

条件操作符

exp1 ? exp2 : exp3
exp1成立,exp2计算,整个表达式结果是exp2的结果
exp1不成立,exp3计算,整个表达式结果是exp3的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
int a = 0;
int b = 3;
int max = 0;

if (a>b)
max = a;
else
max = b;

max = a > b ? a : b;//二者等价

return 0;

}

逗号表达式

exp1, exp2, exp3
从左向右依次计算,整个表达式的结果是最后一个表达式的结果

下标引用、函数调用、结构成员

[]  ()  .  ->

常见关键字

auto

是自动的,每个局部变量都是auto修饰的

register

寄存器关键字
大量频繁使用的数据放在里面提高使用效率

signed

有符号的

unsigned

union

联合体(共用体)

typedef

类型重定义,重命名(别名)

1
2
3
4
5
6
7
8
typedef unsigned int u_int;//给unsigned int搞个别名u_int;
int main()
{
unsigned int num = 100;
u_int num2 = 100;

return 0;
}

void

无-空

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void test()
{
int a = 1;//a作为局部变量每次出括号就销毁,每次调用test函数又从1重新赋值a++=2
a++;
printf("%d ", a);
}

int main()
{
int i = 0;
while (i<10)
{
test();
i++;
}
return 0;
}

static

静态的,本质是改变了变量a的存储类型

  • 修饰局部变量
    让局部变量变成类似全局变量
  • 修饰全局变量
    把全局变量的外部链接性改为内部链接性(静态),使得这个全局变量不能被其他文件连接使用
  • 修饰函数
    使得函数只能在自己所在的源文件内部使用,其他源文件不能使用
    本质上是改变链接属性(外部->内部),和修饰全局变量类似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void test()
{
static int a = 1;//改变了变量a的存储类型
a++;
printf("%d ", a);
}

int main()
{
int i = 0;
while (i<10)
{
test();
i++;
}
return 0;
}

内存划分

备注
栈区 局部变量,函数的参数
堆区 动态内存分配的!!
静态区 全局变量,static修饰的静态变量

extern

声明外部符号

  • 可以声明变量
  • 可以声明自定义函数
1
2
3
4
5
6
7
extern g_val = 500;

int main()
{
printf("%d\n", g_val);
return 0;
}
  • static修饰全局变量,使得这个全局变量只能在自己的源文件(.c)文件内部使用,其他源文件不能使用!
  • 全局变量在其他源文件内可以使用是因为全局变量具有外部连接属性
  • 被static修饰之后就变成了内部连接属性,其他源文件就不能连接到这个静态的全局变量了

常量和宏

define

define 是一个预处理指令

用法如下两种:

define定义符号

定义常量

1
2
3
4
5
6
#define MAX 1000
int main()
{

return 0;
}

define定义宏

1
2
3
4
5
6
7
8
#define ADD(X, Y) X+Y

int main()
{
printf("%d\n", 4*ADD(2, 3));
//结果是11,因为定义宏相当于替换,也就是变成4*2+3=11
return 0;
}
1
2
3
4
5
6
7
8
#define ADD(X, Y) ((X)+(Y))

int main()
{
printf("%d\n", 4*ADD(2, 3));
//这个时候乘的就是X+Y整体,4*(2+3)=20
return 0;
}

指针

内存

  • 内存编号

  • 内存单元的大小

进制
32位 32根地址线 通电 1/0
64位 64根地址线 ^ ^

地址线通电与否的电信号转换为0或1的数字信号

32位有2322^{32}个内存单元

如果一个内存单元是一个比特

232=4,294,967,296 bit2^{32} = 4,294,967,296\ bit比特位
4,294,967,296/8=536,870,912 byte4,294,967,296/8 = 536,870,912\ byte除以8等于字节
536,870,912/1024=524,288 KB536,870,912/1024 = 524,288\ KB
524,288/1024=512 MB524,288/1024 = 512\ MB
512/1024=0.5 GB512/1024 = 0.5 \ GB
32位内存就为0.5GB

一个内存单元是一个字节,然后编号

==32位内存为4GB==

1比特在32位平台是四个字节,64位平台是八个字节

为了有效使用内存,把内存划分为一个个小的内存单元,每个内存单元大小是1个字节

为了能够有效访问到内存的每个单元,就给内存单元进行编号,这些编号被称为该内存单元的地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
int a = 10;//a在内存中要分配空间(4个字节)
//&a拿到的是第一个字节的地址
printf"(%p\n", &a);//%p专门用来打印地址
int* pa = &a;//pa是用来存放地址的,在C语言中叫做指针变量
//*说明pa是指针变量
//int说明pa指向的对象是int类型的
//&是取地址操作符

//例如
char ch = "w";
char* pc = &ch;

return 0;
}
1
2
3
4
5
6
7
int main()
{
int num = 10;
int* p = &num;
*p = 20;//*是解引用操作符,是一个单目操作符,*pa就是通过pa里面的地址找到a
return 0;
}

通过p找到num

==指针就是地址==

指针的大小

由于指针用来存放地址,地址有多大,指针就有多大,因此==指针的大小是相同的==

位数 比特 字节
32位(x86) 32bit 4byte
64位(x64) 64bit 8byte

结构体

描述复杂对象

结构体让C语言创建新的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//创建一个学生类型
struct Stu
{
char name[20];
int age;
double score;//结构里的成员,成员变量
}
//创建一个book类型
struct Book
{
char name[20];
float price;
char id[30];
}

int main()
{
struct Stu s = {"张三"2085.5};//结构体的创建和初始化。对应上面三项,第一项是字符所以加引号
printf("%s %d %f\n", s.name, s.age, s.score);
// '.操作符',找到结构体的成员变量
//结构体变量.成员变量
struct Stu * ps = &s;//放到指针变量
printf("%s %d %f\n", (*ps).name, (*ps).age, (*ps).score);结果和上面等价
//结构体指针.各变量
printf("%s %d %f\n", ps->name, ps->age, ps->score);//先找到ps,再指向ps里的各变量,
//结构体指针->成员名
return 0;
}