库函数
C语言本身提供给我们的函数;
整型长度(字节):
char -> 1
short -> 2
int -> 4
long -> 4/8
long long -> 8
float -> 4
double -> 8
计算机中的单位bit->比特位
short age = 20;//向内存申请2个字节-16bit位,用来存放20;
C语言规定只要sizeof(long) >= sizeof(int)就可以了,并没有规定说long的长度一定是4或者8;
变量
- 1.当局部变量名与全局变量名一致时,在函数内部优先使用局部变量;建议局部变量名和全局变量名不相同;
- 2.全局变量的作用域是整个工程;
变量的生命周期
变量的生命周期是指变量创建到销毁的一个时间段;
1.局部变量的生命周期:进入作用域生命周期开始,出作用域生命周期结束;
2.全局变量的生命周期:整个程序的生命周期;
放在大括号内的都是局部变量;
& 取地址
scanf_s()
输出函数
问题1根据提示 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.
- 1.在文件顶部第一行加入一行:#define _CRT_SECURE_NO_WARNINGS
- 2.使用scanf_s,而不是scanf;
scanf是C语言提供的
scanf_s不是标准C语言提供的,是VS编译器提供的,一般不建议使用scanf_s();scanf_s没有跨平台性和移植性;
文件创建时添加申明
app\Common7\IDE\VC\VCProjectItems\newc++file.cpp
#define _CRT_SECURE_NO_WARNINGS 1
extern
申明外部符号
常量
字面常量
const
修饰的常变量,常量不可变;const int num = 9;
常变量:本质是变量,但是有常量的属性;int arr[length] = {0};会报错"表达式必须含有常量值",数组定义只能为int arr[10] = {0};
#define
定义的标识符常量
#define MAX 10;
int arr[MAX] = {0};//并没有报错,说明是常量;
- 枚举常量
enum Gender {
MALE,
FEMALE,
SECRT
};
enum Sex s = FEMALE;
printf("%d\n\t", s); //1
printf("%d\n\t", MALE); //0
printf("%d\n\t", SECRT); //2
字符串+转义字符+注释
字符串的结束标志是一个
\0
的转义字符。在计算字符串长度的时候\0
是结束标志,不算作字符串内容,不管\0
后面有没有值都不做处理。
char chars[] = "abc";//数组
在这个chars变量的内容是
'a','b','c','\0'
;其中'\0'
的意思是字符串的结束标志,而'\0'
的值是0
;
printf("%s\n", chars);
输出
abc
char chars[] = {'a','b','c'};//数组
printf("%s\n", chars);
输出
abc烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫虜惀?
分析
为什么会出现乱码? 程序在输出数组
chars
的内容时因为没有\0
,字符c
后面是随机值,一直等遇到\0
程序才输出结束;而\0
的意思是,如果主动添加\0
,程序就会正常输出;
char chars[] = {'a','b','c','\0'};//数组
printf("%s\n", chars);
输出
abc
转义字符
转变原来的意思
转义字符 | 释义 |
---|---|
\? | 在书写连续多个问号时使用,防止他们被解析成三个母词(??+) ) |
\’ | 表示用于字符常量' |
\" | 标识一个字符串内部的双引号 |
\\ | 用于表示一个反斜杠,防止它被解释为一个转义序列符 |
\a | 警告字符,蜂鸣(系统提示音) |
\b | 退格符 |
\f | 进纸符 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ddd | ddd 表示1~3个八进制的数字。如: 130X;作为8进制代表的那个十进制数字,作为ASCII码值对应的字符,比如 \32 是八进制,转换为十进制就是26,对应的ASCII字符为➡ |
\xdd | dd表示2个十六进制数字。如:\x255 |
异或
计算规律:对应的二进制位相同,则为0;对应的二进制位相异,则为0;
公式
a^b=(!a&b)|(a&!b)
复合赋值符
+=
-=
*=
%=
/=
*=
>>=
<<=
|=
^=
单目操作符
! 逻辑反操作(C语言中表示真假:0-假;非0-真)
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
只要是整数,内存中存储的都是二进制的补码;
原码 反码 补码;
原码=补码-1取反;
反码=补码-1;
int a = 10;
int b = a++;
printf(" a=%d ,b=%d\n", a, b);
a++是后置++,先用后加,所以b=10,a=11;
int a = 10;
int b = ++a;
printf(" a=%d ,b=%d\n", a, b);
++a是前置++,先加后赋值,所以a=11,b=11;
&&
int a = 10;
int b = 5;
int c = a && b;
printf("%d\n", c);
在逻辑运算中,假:0;真:非0;
EOF
end of file:文件结束标志,值为-1
逗号表达式
exp1,exp2,exp3,exp4,...expN
()
函数调用操作符(调用方法时的方法括号)
常见关键字
auto 自动变量
auto int a = 10;//局部变量;在作用域内自动创建,自动销毁;默认省略auto;
register 寄存器
计算机存储数据:寄存器->高速缓存->内存->硬盘
register int a = 10;//建议把a定义为寄存器变量;
signed 有符号
可以存放正数或复数,当定义一个整型变量的时候,默认是signed的;默认省略。
unsigned 无符号
只可以存放正数;
unsigned int a = -1;
printf("%u\n", a);
输出结果
4294967295
extern 外部变量申明
typeof 类型定义(类型重定义)
unsigned int num = 20;
//使用typeof重新定义
typeof unsigned int u_int;
u_int num = 20;
关键字static
static是用来修饰变量和函数;
- 修饰局部变量-静态局部变量:局部变量的生命周期延长
每调用一次testMethod
函数,num
局部变量加1
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void testMethod() {
int num = 0;//静态的局部变量
num++;
printf("%d\n", num);
}
int main() {
int i = 0;
while (i < 5 ) {
i++;
testMethod();
}
return 0;
}
程序输出结果:
1
1
1
1
1
程序分析:
局部变量num
的生命周期随着函数testMethod
的结束而结束,导致每次调用testMethod
函时,局部num
都输出1。如果想输出累加的效果,则需要将局部变量num
的生命周期延长,这时就用到了static
关键字。C2371
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
void testMethod() {
static int num = 0;//静态的局部变量
num++;
printf("%d\n", num);
}
int main() {
int i = 0;
while (i < 5 ) {
i++;
testMethod();
}
return 0;
}
程序输出结果:
1
2
3
4
5
- 修饰全局变量-静态全局变量
改变了变量的作用域,–让静态的全局变量只能在自己所在的源文件内部使用。出了源文件就没法再使用了。
constant.c
#define _CRT_SECURE_NO_WARNINGS 1
int age = 18;
Hello.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
extern int age;
printf("%d\n", age);
return 0;
}
程序输出结果
18
如果给源文件
Constant.c
中的age
用static
修饰呢?
constant.c
#define _CRT_SECURE_NO_WARNINGS 1
static int age = 18;
程序输出结果
LNK2001:无法解析的外部符号age
程序分析
从运行结果来看,给全局变量增加
static
关键字会使该变量的作用域降低。就有该结论: 改变了变量的作用域,—让静态的全局变量只能在自己所在的源文件内部使用。出了源文件就没法再使用了。
- 修饰函数-静态函数
static修饰函数改变了函数的链接属性。普通方法是有外部链接属性,由static修饰的函数外部链接属性变为内部链接属性。
CalculateUtil.c
#define _CRT_SECURE_NO_WARNINGS 1
int Add(int x, int y) {
return x + y;
}
Main_exec.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
extern int Add(int x, int y);//可以省略
int main() {
int num1 = 20;
int num2 = 30;
int num3 = Add(num1, num2);
printf("%d\n", num3);
return 0;
}
程序输出结果
50
给Add函数添加
static
关键字
CalculateUtil.c
#define _CRT_SECURE_NO_WARNINGS 1
static int Add(int x, int y) {
return x + y;
}
程序分析
执行
Main_exec.c
后会发现报错```LNK2019 | 无法解析的外部符号 Add,函数 main 中引用了该符号。
得出结论:static修饰函数改变了函数的链接属性。普通方法是有外部链接属性,由static修饰的函数外部链接属性变为内部链接属性。
#define 定义常量和宏
#define
定义标识符常量
Main_exec.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#define MAX 100;
int main() {
int num1 = MAX;
printf("%d\n", num1);
return 0;
}
#define
定义宏—带参数
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#define MAX(x,y )(x > y ? x : y);
int max(int x, int y) {
return x > y ? x : y;
}
int main() {
int num1 = 10;
int num2 = 20;
int num3 = max(num1, num2);//普通函数
int num4 = MAX(num1, num2);//宏的方式
printf("%d\n", num3);
printf("%d\n", num4);
return 0;
}
指针
用来存放地址的变量—指针
内存
内存是计算机上特别重要的存储器,计算机中所有程序的运行都是再内存中进行的。
所以为了有效的使用内存,就把内存划分为一个个小的内存单元,每个内存单元的大小是1个字节。
为了能够有效的访问到内存的每个单元,就给内存单元进行编号,这些编号被称为该内存单位的地址。
1byte = 8bit
如何产生地址
32位: 32根地址线/数据线;正电(1)和负电(0)的区分。
int a = 10;//4个字节
int* p = &a;//取地址
printf("%p\n",&a);//打印地址
int c = *p;//*-解引用操作符,*p:找到*p所指向的对象
printf("%d\n", c);
*p = 20;
printf("%d\n", a);
程序输出结果:
000000D3224FF954
10
20
指针变量的大小
printf("%d\n", sizeof(char *));
printf("%d\n", sizeof(short *));
printf("%d\n", sizeof(int *));
printf("%d\n", sizeof(double *));
结论: 指针大小在32位平台是4个字节,64位平台是8个字节。
32bit = 4byte;
结构体
结构体是C语言中特别重要的知识点,结构体使得C语言有能力描述复杂类型。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
//创建结构体类型
struct Book {
char name[20];
char type[20];
double price;
double discount;
double actualPrice;
};
int main() {
//利用结构体类型创建一个该类型的结构体变量出来
struct Book book1 = { "《重构》","架构",99.8,0.88,0.0};
struct Book* bookAddr = &book1;
printf("书名:%s\n",book1.name);
printf("书类型:%s\n",book1.type);
printf("价格:%lf\n",book1.price);
//计算实际价格
book1.actualPrice = book1.price * book1.discount;
printf("实际价格为:%lf\n", book1.actualPrice);
printf("书修改前的类型:%s\n", book1.type);
strcpy(book1.type , "计算机/软件工程");//给book1.type赋值
printf("书修改后的类型:%s\n", (*bookAddr).type);//type本质上是个地址
printf("书修改后的类型:%s\n", bookAddr->type);
return 0;
}
程序输出结果:
书名:《重构》
书类型:架构
价格:99.800000
实际价格为:87.824000
书修改前的类型:架构
书修改后的类型:计算机/软件工程
书修改后的类型:计算机/软件工程
程序分析:
直接使用
book1.type = "计算机/软件工程";
是不行的,因为type
的类型是数组,无法直接进行赋值,需要使用strcpy(book1.type , "计算机/软件工程");
即可;