目录
一、变量
1.变量类型所占字节
char :1个字节
*(即指针变量): 4个字节/8个字节(在不同(32位/64位)编译器上不同)
short int : 2个字节
int: 4个字节
unsigned int : 4个字节
float: 4个字节
double: 8个字节
long: 4个字节/8个字节(规定:sizeof(long)>=sizeof(int)即可,在不同(32位/64位)编译器上不同)
long long: 8个字节
unsigned long: 8个字节
2.局部变量和全局变量
当局部变量和全局变量名字冲突时,局部优先
3.scanf()和scanf_s()
(1)scanf():使用时在第一行或在*newc++ file.cpp文件中加
#define _CRT_SECURE_NO_WARNINGS 1
(2)scanf_s():传入一个和参数有关的大小值,避免引用到不存在的元素,防止hacker利用原版的不安)全性(漏洞)黑掉系统-->更安全
切记键盘输入是要少敲一位字符,因为数组最后一位要放结束符
例:char[20]-->scanf_s("%s",d,20);//表示最多取19个字符
键盘响应输入的问题
第一种情况:
当我们scanf_s("%d%d%d",a,b,c);
如果你在键盘上输入了1 2 3(1空格2空格3),那么第一个空格就被当作字符了,要用回车来输入,键盘的按键顺序就是:1 Enter 2 Enter 3 Enter。
第二种情况:
当我们scanf_s("%d,%d,%d",a,b,c);
这个时候我们就需要用逗号隔开,比如想给a输入1,b输入2,c输入3。键盘的按键顺序就是:1 逗号 2 逗号 3 Enter
4.extern
在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。
(1)extern修饰变量的声明。
举例来说,如果文件a.c需要引用b.c中变量int v,就可以在a.c中声明extern int v,然后就可以引用变量v。能够被其他模块以extern修饰符引用到的变量通常是全局变量。还有很重要的一点是,extern int v可以放在a.c中的任何地方,比如你可以在a.c中的函数fun定义的开头处声明extern int v,然后就可以引用到变量v了,只不过这样只能在函数fun作用域中引用v罢了,这还是变量作用域的问题。对于这一点来说,很多人使用的时候都心存顾虑。
//源.c文件
int x=1;
//test.c文件
extern int x;
int main()
{
return x;
}
(2) extern修饰函数声明。
从本质上来讲,变量和函数没有区别。函数名是指向函数二进制块开头处的指针。如果文件a.c需要引用b.c中的函数,比如在b.c中原型是int fun(int mu),那么就可以在a.c中声明extern int fun(int mu),然后就能使用fun来做任何事情。就像变量的声明一样,extern int fun(int mu)可以放在a.c中任何地方,而不一定非要放在a.c的文件作用域的范围中。对其他模块中函数的引用,最常用的方法是包含这些函数声明的头文件。
(3) 此外,extern修饰符可用于指示C或者C++函数的调用规范。
比如在C++中调用C库函数,就需要在C++程序中用extern “C”声明要引用的函数。这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。主要原因是C++和C程序编译完成后在目标代码中命名规则不同。
二、常量
1.字面常量
2.const 修饰常变量
const int n=10;//n不能再被重新赋值
int arr[n]={0};//n为变量,error
3.#define定义的标识符常量
#define MAX 10000
int main()
{
//MAX=100;//error!不可以修改值的大小
int n=MAX;
printf("%d",n);
}
4.枚举常量
用于可以一一列举的常量
关键字:enum
#include<stdio.h>
enum SEX
{
//这种枚举类型的变量的未来可能取值,值默认从0开始,不可以修改
MALE,
FEMALE,
SECRECT
};
int main()
{
enum Sex s=MALE;
//MALE=3;//error
printf("%d\n",MALE);
printf("%d\n",FEMALE);
printf("%d\n",SECRECT);
return 0;
}
输出:
三、字符串
1.定义方式
char arr[]="hello";
2.结束标志
字符串的结束标志是一个 \0 的转义字符,在计算字符串长度时 \0 是结束标志,不算做字符串内容。
3.字符串与字符数组
char arr1[]="abc";
char arr2[]={'a','b','c'};
//打印
printf("%s\n",arr1);
printf("%s\n",arr2);
输出结果;
arr1在内存中的内容:a b c \0 arr2在内存中的内容:a b c (其余为乱码)
printf("%d\n", strlen(arr1));
printf("%d\n", strlen(arr2));
输出结果:
arr1的长度为字符个数 arr2的长度为随机值
4.转义字符
转变了字符原来的意思
转义字符 | 意义 |
\a | 响铃(BEL) |
\b | 退格(BS) ,将当前位置移到前一列 |
\f | 换页(FF),将当前位置移到下页开头 |
\n | 换行(LF) ,将当前位置移到下一行开头 |
\r | 回车(CR) ,将当前位置移到本行开头 |
\t | 水平制表(HT) (跳到下一个TAB位置) |
\v | 垂直制表(VT) |
\\ | 代表一个反斜线字符''\' |
\' | 代表一个单引号(撇号)字符 |
\" | 代表一个双引号字符 |
\? | 代表一个问号 |
\0 | 空字符(NUL) |
\ddd | 1到3位八进制数所代表的任意字符,如:\130 |
\xhh | 十六进制所代表的任意字符,,如:\x30 0 |
printf("%c\n", '\130');
输出:
表示:八进制130等于十进制88(ASCII:X)
ASCII对照表:
例:
printf("%d\n", strlen("c:\test\328\test.c"));
输出:
四、选择语句
int main()
{
int input = 0;
printf("小聪明聪明嘛(1/0)?\n");
scanf_s("%d", &input);
if (input == 1)
printf("nice!bro");
else
printf("打洗你");
return 0;
}
输出:
五、循环语句
int main()
{
int day = 1;
while (day <= 300)
{
printf("第%d天:背单词\n", day);
day++;
}
printf("四六级过了!");
return 0;
}
输出:
六、函数
int sum(int num1, int num2)
{
return num1 + num2;
}
int main()
{
int num1 = 0,num2 = 0;
scanf_s("%d%d", &num1, &num2);
printf("%d", sum(num1, num2));
return 0;
}
输出:
七、数组
定义:一组相同类型元素的集合
数组是用下标来访问的,第一个元素下标为0
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };//10个整形1-10存起来
//char ch[5] = { 'a','b','c' };//不完全初始化,剩余的默认初始化为0
int i = 0;
while (i < 10)
{
printf("%d\n", arr[i]);
i++;
}
return 0;
}
输出:
八、操作符
算数操作符 | + - * / % |
移位操作符 | << >> |
位操作符 | & 按位与 ^ 按位或 | 按位异或 |
赋值操作符 | = += -= /= &= ^= |= %= >>= <<= |
单目操作符 (只有一个操作数) | ! 逻辑反操作 - 负值 + 正值 & 取地址 sizeof 操作数的类型长度(以字节为单位) ~ 对一个数的二进制按位取反 -- 前置、后置-- ++ 前置、后置++ * 间接访问操作符(解引用操作符) (类型) 强制类型转换 |
关系操作符 | > >= < <= != == |
逻辑操作符 | && || |
条件操作符 (三目操作符) | exp1 ? exp2 : exp3 |
逗号表达式 | exp1, exp2, exp3, ...expN |
下标引用操作符 | [] |
函数调用操作符 | () |
结构成员 | . -> |
1.移位操作符
移位操作符移动的是二进制位
例:
int main()
{
int a = 2;
int b = a << 1;
printf("%d", b);
return 0;
}
a:00000000000000000000000000000010
b:00000000000000000000000000000100
输出:
2.单目操作符
(1)sizeof后面的括号可以省略<--sizeof为单目运算符
(2)~(按位取反):把所有二进制位中数字,1变成0,0变成1
int main()
{
int a = 0;
printf("%d\n", ~a);
return 0;
}
a:00000000000000000000000000000000
~a:11111111111111111111111111111111
整数在内存中存储的是补码
一个整数的二进制表示有三种:原码、反码、补码
-1的二进制表示(以下方法针对负整数,正整数的原码、反码、补码相同):
原码:10000000000000000000000000000001(第一位为符号位)
反码:11111111111111111111111111111110(符号位不变,原码其他位按位取反)
补码:11111111111111111111111111111111(符号位不变,反码+1)
输出:
(3)(类型):强制类型转换
int a=(int)3.14;
3.逻辑操作符
int main()
{
int a = 3;
int b = 5;
int c = 0;
printf("%d\n", a && b);
printf("%d\n", a && c);
printf("%d\n", a || c);
return 0;
}
输出:
4.条件操作符
exp1?exp2:exp3 :exp1成立,exp2计算,整个表达式的结果是:exp2的结果 exp1不成立,exp3计算,整个表达式的结果是:exp3 的结果
int main()
{
int a = 0;
int b = 3;
int max=a > b ? a : b;
printf("%d", max);
return 0;
}
输出:
5.逗号表达式
逗号表达式:逗号隔开的一段表达式
从左到右依次计算,整个表达式的结果是最后一个表达式的结果
int main()
{
int a = 0;
int b = 3;
int c = 5;
int d = (a = b + 2, c = a - 4, b = c + 2);
printf("%d\n", d);
return 0;
}
输出:
九、常见关键字
是c语言提供的,不能自己创建关键字
关键字不能作为变量名
1.auto:修饰局部变量--自动创建,自动销毁,一般省略
auto int a=0;//自动变量
2.extern:用来修饰外部符号
3.register:寄存器关键字
大量频繁被使用的数据,放在寄存器中,提升效率
register int num = 100;//建议num的值存放在寄存器中
计算机中数据可以存放到哪里呢?
网盘——2T-免费,依赖网络,传输速率慢
硬盘——500G-买的,传输速率较快
内存——8-16G,传输速率快
高速缓存——几十MB,传输速率更快
寄存器——更小,传输速率最快
-->造价越高,速度越快,空间越小
4.signed:有符号的
unsigned:无符号的
5.union:联合体(共用体)
6.void:无、空
7.define、include不是关键字,是预处理指令
8.typedef:类型重定义,别名
//类型重命名
typedef unsigned int u_int;
int main()
{
unsigned int nim = 100;
u_int num = 100;
return 0;
}
9.static:静态的
(1)修饰局部变量:改变了局部变量的生命周期(本质上是改变了变量的存储类型)
void test()
{
static int a = 1;
a++;
printf("%d ", a);
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}
加上static后,a存储在静态区,代码在执行完test()函数后仍不销毁,仍保留原来的值
输出:
(2)修饰全局变量,使得这个 全局变量只能在自己所在的源文件内部使用,其他源文件不能使用
全局变量在其他源文件内部可以被使用,这是因为全局变量具有外部链接属性,但是被static修饰之后,就变成了内部链接属性,其他源文件就不能链接到这个静态的全局变量了
输出:
(3)修饰函数,使得函数只能在自己所在的源文件内部使用,不能在其他源文件内部使用
本质上,static是将函数的外部链接属性变成了内部链接属性
输出:
十、define定义常量和宏
define:是一个预处理指令
1.定义符号
#define MAX 100
int main()
{
printf("%d", MAX);
return 0;
}
输出:
100
2.定义宏
例:计算4*(2+3)
#define ADD(X,Y) X+Y
int main()
{
printf("%d", 4*ADD(2,3));
return 0;
}
输出:
11
这是因为实际计算的其实是
应注意宏的书写方法
#define ADD(X,Y) ((X)+(Y))
int main()
{
printf("%d", 4*ADD(2,3));
return 0;
}
输出:
20
十一、指针
1.内存:是电脑上特别重要的存储器,计算机中所有程序的运行都是在内训中完成的。
所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节,为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为内存单元的地址。
2.指针变量--用来存放地址(指针就是地址)
int main()
{
int a = 10;//在内存中分配空间--4个字节
printf("%p\n", &a);//%p--打印地址
int* pa = &a;//pa--用来存放地址,称为指针变量
return 0;
}
* 说明pa是指针变量
int 说明pa执行的对象是int类型的
输出:
010FFA18
3.解引用操作:*pa通过pa里面的地址,找到a
int main()
{
int a = 10;
int* pa = &a;
*pa = 20;
printf("%d\n", a);
return 0;
}
输出:
20
4.指针变量的大小
int main()
{
printf("%d", sizeof(char*));
printf("%d", sizeof(short*));
printf("%d", sizeof(int*));
printf("%d", sizeof(long*));
printf("%d", sizeof(long long*));
printf("%d", sizeof(float*));
printf("%d", sizeof(double*));
return 0;
}
输出:
4444444
所有指针变量的大小都是一样的(4个字节/8个字节)
这是因为,指针是用来存放地址的,指针需要多大空间,取决于地址的存储需要多大空间
32位平台-32bit--4字节
64位平台--64bit--8字节
十二、结构体
结构体是用来描述复杂对象的
例如:描述一个学生,包括 姓名、年龄、性别 等信息
共有三种输出方式:
int main()
{
struct Stu s = { "xcm",20,95.50};//结构体创建和初始化
//输出方式1
printf("%s %d %lf\n", s.name, s.age, s.score);//格式:结构体变量.成员变量
//输出方式2
struct Stu* ps = &s;
printf("%s %d %lf\n", (*ps).name, (*ps).age, (*ps).score);
//输出方式3
printf("%s %d %lf\n", ps->name, ps->age, ps->score);
return 0;
}
输出: