C语言进阶知识点总结

思维导图的分享:
链接:https://www.zhixi.com/view/bcfc68f7
密码:4532

C语言进阶

深度解析数据在内存中的存储

数据类型详细介绍

类型的意义
使用类型开辟空间的大小(大小决定了使用范围 )
如何看待空间的角度
类型的基本归类
整形家族
char

unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]

浮点型家族
float

double

构造类型
数组类型
结构体类型 struct
联合体类型 union
枚举类型 enum
指针类型
int *pi;

char pc;
float
pf;
void* pv;

空类型
void 表示空类型(无类型)

通常应用于函数的返回类型、函数的参数、指针类型。

整形在内存中的存储:原码、反码和补码

整数有符号位和数值位,符号:0表示正数,1表示负数。剩下的数值位就是通过原码、反码和补码的形式来表示的。
正数的原码、反码和补码相同
负数
原码:符号为1,剩下的数值是二进制表示的数值
反码:将原码的符号位不变,剩下的位按位取反
补码:反码加1
这样储存整形的意义
使用补码,可以将符号位和数值域统一处理
如果以最高位为符号位,二进制原码最大为0111111111111111=2的15次方减1=32767

最小为1111111111111111=-2的15次方减1=-32767
此时0有两种表示方法,即正0和负0:0000000000000000=1000000000000000=0
所以,二进制原码表示时,范围是-32767~-0和0~32767,因为有两个零的存在,所以不同的数值个数一共只有2的16次方减1个,比16位二进制能够提供的2的16次方个编码少1个。
但是计算机中采用二进制补码存储数据,即正数编码不变,从0000000000000000到0111111111111111依旧表示0到32767,而负数需要把除符号位以后的部分取反加1,即-32767的补码为1000000000000001。
到此,再来看原码的正0和负0:0000000000000000和1000000000000000,补码表示中,前者的补码还是0000000000000000,后者经过非符号位取反加1后,同样变成了0000000000000000,也就是正0和负0在补码系统中的编码是一样的。但是,我们知道,16位二进制数可以表示2的16次方个编码,而在补码中零的编码只有一个,也就是补码中会比原码多一个编码出来,这个编码就是1000000000000000,因为任何一个原码都不可能在转成补码时变成1000000000000000。所以,人为规定1000000000000000这个补码编码为-32768。
所以,补码系统中,范围是-23768~32767。
因此,实际上,二进制的最小数确实是1111111111111111,只是二进制补码的最小值才是1000000000000000,而补码的1111111111111111是二进制值的-1

加法和减法可以统一处理(CPU只有加法器)
其运算过程,不需要额外的电路

大小端字节序介绍和判断

大端
大端存储模式,是指数据低字节位存储到高地址处,高字节位存储到低地址处
小端
小端存储模式,是指数据低字节位存储到地址处,高字节位存储到高地址处

浮点型在内存中存储解析

浮点数的存储规则
任何二进制的浮点数都可表示成
(-1)^S * M * 2^E

(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。

IEEE 754规定:
32位的浮点数:最高的1位表示符号位s,接着8位数表示指数E,剩下的23位表示位有效数字M
64位的浮点数:最高的1位表示符号位s,接着11位数表指数E,剩下的52位表示有效数字M
前面说过, 1≤M<2 ,也就是说,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。

IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的
xxxxxx部分。比如保存1.01的时
候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位
浮点数为例,留给M只有23位,
将第一位的1舍去以后,等于可以保存24位有效数字。

对于E的规则
  • 首先是,E是无符号整数

    • 这意味着,如果E为8位,它的取值范围为0255;如果E为11位,它的取值范围为02047。但是,我们
      知道,科学计数法中的E是可以出
      现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,
      对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。
      比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即
      10001001。
  • E不全0和不全为1

    • 这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将
      有效数字M前加上第一位的1。

      • 比如:
        0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为
        1.0*2^(-1),其阶码为-1+127=126,表示为
        01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进
        制表示形式为: 0 01111110 00000000000000000000000
  • E全为0

    • 这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,
      有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于
      0的很小的数字。
  • E全为1

    • 这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);

指针进阶

字符指针

类型:char*
使用
指向一个字符
int main()

{
char ch = ‘w’;
char *pc = &ch;
*pc = ‘w’;
return 0;
}

指向一个字符串
int main()

{
const char* pstr = “hello bit.”;
printf(“%s\n”, pstr);
return 0;
}

指向一个字符的时候,通过该指针可以改变该字符的内容。
指向一个字符串的时候,并不是把整个字符串存储到该指针里面,而是把字符串的首地址赋值给该指针,通过指针可以访问这个字符串;

此时的字符串是常量字符串,不能被修改

数组指针

数组指针表示的是存放指针的数组
int* arr1[10]; //整形指针的数组

char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

指针数组

定义:能够指向数组的指针
int (*p)[10];

//解释:p先和结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个
指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于
号的,所以必须加上()来保证p先和*结合。

&数组名VS数组名
实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。(细细体会一下)

本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型
数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40.

数组名表示首元素的地址,步长表示的元素的大小
数组指针的使用
接受二维数组的数组名的指针

数组传参和指针传参

一维数组传参
函数参数设计
一维数组,不带长度
一维数组,带长度
一级指针
二维数组传参
函数参数设计
二位数组,列一定要清楚长度
数组指针,表明指向的数组有多长(即列的长度)

函数指针

函数指针的定义和声明:存在函数—— int *add(int x, float y)
定义
int * (*p) (int x ,int y)=add
  • 此时的指针P指向的就是函数add
声明
int * (*)(int ,int)
函数名和函数指针都表示函数的地址

函数指针数组

定义:int (*parr1[10])();
函数指针数组的用途之一是用于转移表,此时数组里面的函数——参数类型相同,返回类型也是相同的

指向函数指针数组的指针

如何定义
void test(const char* str)

{
printf(“%s\n”, str);
}
int main()
{
//函数指针pfun
void (pfun)(const char) = test;
//函数指针的数组pfunArr
void (pfunArr[5])(const char str);
pfunArr[0] = test;
//指向函数指针数组pfunArr的指针ppfunArr
void (*(ppfunArr)[5])(const char) = &pfunArr;
return 0;
}

回调函数

定义
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
qsort函数
第一个参数:数组名
第二个参数:数组元素个数
第三个参数:数组元素的大小
第四个参数:数组类型的比较函数的地址
qsort的使用的快速排序的思想

使用比较函数的地址作为参数
此时就是回调函数的使用实例

字符函数和字符串函数解析

求字符串长度

strlen
函数只有一个参数:表示的一个字符串首字符的地址
用途:求一个字符串的长度,以’\0’结尾
返回值是无符号整数

长度不受限制的字符串函数

strcpy
函数有两个参数:第一个参数表示的是目标空间的地址,第二参数表示的要拷贝字符串的首地址
用途:将一个字符串复制到另一个字符数组中
返回值是目标空间的首地址
strcat
函数有两个参数:第一个参数表示的是目标空间的地址,第二参数表示的要拷贝字符串的首地址
用途:将字符串接到目标空间字符串的末尾处
返回值是目标空间字符串的首地址
strcmp
函数有两个参数:分别是两个比较字符串的首地址
用途:用来比较两个字符串大小
标准规定:

第一个字符串大于第二个字符串,则返回大于0的数字;
第一个字符串等于第二个字符串,则返回0;
第一个字符串小于第二个字符串,则返回小于0的数字。

长度受限制的字符串函数

strncpy
函数有三个参数:第一个参数表示的是目标空间的地址,第二参数表示的要拷贝字符串的首地址;第三个参数是整数,表示要拷贝几个字符
用途:指定num个源字符串拷贝到目标空间。
返回值是目标空间的字符串的首地址
strncat
函数有三个参数:第一个参数表示的是目标空间的地址,第二参数表示的要拷贝字符串的首地址;第三个参数是整数,表示要接几个字符。
用途:指定num个字符从源字符串中接到目标空间处。
返回值是目标空间的字符串的首地址
strncmp
函数有三个参数:分别是两个比较字符串的首地址;第三个参数是整数,表示要比较num个字符
用途:比较num个字符。
标准规定:

第一个字符串大于第二个字符串,则返回大于0的数字;
第一个字符串等于第二个字符串,则返回0;
第一个字符串小于第二个字符串,则返回小于0的数字。

字符查找函数

strstr
函数有两个参数:第一个是str1,表示在str1寻找子字符串str2;第二个参数str2,表示的是子字符串
用途:判断在str1中是否有str2的字符串。
(1)在str1找的第一个str2字符串的位置,直接返回该位置。

(2)未找到的话,返回的是NULL。

strtok
函数有两个参数:第一个参数是将要被分割的字符串;第二参数表示的分割标志符的集合——字符串的形式
用途:将特定的字符串,以若干个分割符隔开。
使用的方法(循环表示)
int main()

{
//char arr[] = “zpengwei@yeah.net”;//“@.”
char arr[] = “192#168.120.85”;
char* p = “#.”;
char buf[20] = { 0 };//“zpengwei\0yeah\0net”
strcpy(buf, arr);
char* ret = NULL;
for (ret = strtok(buf, p); ret != NULL; ret=strtok(NULL, p))
{
printf(“%s\n”, ret);
}

//char* ret = strtok(buf, p);
//printf("%s\n", ret);
//ret = strtok(NULL, p);
//printf("%s\n", ret);
//ret = strtok(NULL, p);
//printf("%s\n", ret);

//zpengwei
//yeah
//net
return 0;

}

错误信息报告

strerror
函数参数只有一个:整数,,表示错误类型的编码

配合头文件errno.h中的errno参数使用

用途:返回错误码,指出错误的信息。

字符操作

字符转化函数
int tolower (int c)//变小写
int toupper(int c)//变大写

内存操作函数

memcpy
函数参数和strncpy一样
memcpy用途可用于全部的数据,是以字节为单位的拷贝
memmove
函数参数:

void * memmove ( void * destination, const void * source, size_t num );

用途:各种数据类型,从源数组拷贝num个字节到指定目标空间里面。可以防止覆盖时候出现的问题。
要点:

(1)和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
(2)如果源空间和目标空间出现重叠,就得使用memmove函数处理。

memset
函数有三个参数:第一个参数表示要修改数组的首元素地址;第二参数表示的是要修改成什么数据;第三个参数表示要修改的几个字节
一般用来设置成0,这是以字节为单位来进行修改的
memcmp
比较各种类型的数据,以字节位单位进行比较
函数参数和strncmp一样

自定义类型:结构体、枚举、联合

结构体

结构体类型的声明
结构体的基础知识:结构是一些值的集合,这些值称为成员变量。结构的每个成 员可以是不同类型的变量。
结构的声明
struct Stu

{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

结构的特殊声明
//匿名结构体类型

struct
{
int a;
char b;
float c;
}x;
struct
{
int a;
char b;
float c;
}a[20], *p;

  • 注意:此时x和*p不是相同的类型
结构的自引用
struct Node

{
int data;
struct Node* next;
};

结构体变量的定义和初始化
结构体内存对齐
对齐规则
1.第一个成员在结构体变量偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍数的地址处

对齐数=编译器默认对齐数和成员大小的较小值;VS默认对齐数是8

3.结构体大小为默认最大对齐数的整数倍数
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己最大对齐数的整数倍处,结构体整个大小就是所以最大对齐数(含嵌套结构体的对齐数)的整数倍。
存在内存对齐的原因
1.平台问题(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2.性能原因:数据结构(尤其是栈)应该尽可能在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作内存访问;而对齐的内存访问只需要一次。
总的来说就是,用空间来换时间
在设计结构体的时候,尽可能让占空间小的成员集中到一起,这样既能节省空间,也能节省时间
修改默认对齐数
之前我们见过了 #pragma 这个预处理指令,这里我们再次使用,可以改变我们的默认对齐数。
  • #include <stdio.h>
    #pragma pack(8)//设置默认对齐数为8
    struct S1
    {
    char c1;
    int i;
    char c2;
    };
    #pragma pack()//取消设置的默认对齐数,还原为默认
结构在对齐方式不合适的时候,我么可以自己更改默认对齐数。
结构体传参
结构体要穿地址
函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
结构体实现位段
位段的定义
位段的声明和结构是类似的,有两个不同:
  • 1.位段的成员必须是 int、unsigned int 或signed int 。(整形家族)

  • 2.位段的成员名后边有一个冒号和一个数字。

位段的内存分配
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
先一个整形的内存开辟,分配空间。不够的内存在重新开辟,一个新的内存。

剩下的内存就浪费掉了。(VS)

位段的跨平问题
1. int 位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。

(16位机器最大16,32位机器最大32,写成 27,在16位机器会出问题。)

3.位段的成员在内存中从左到右分配,还是从右向左分配标准尚未定义
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

枚举

枚举类型的定义
这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。
枚举的优点
1.增加代码的可读性和可维护性
2.和#define定义的标识符比较枚举有类型检查,更加严谨
3.防止命名污染(封装)
4.便于调试
5.使用调试,一次可以定义多个常量
枚举的使用
enum Color//颜色

{
RED=1,
GREEN=2,
BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

联合

联合类型的定义
联合也是一种特殊的自定义类型

这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。

联合的特点
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
联合大小的计算
联合的大小至少是最大成员的大小。

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

动态内存分配

为什么存在动态内存分配

动态内存函数的介绍

malloc和free函数
malloc函数
void* malloc (size_t size);
用途:这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
如果开辟成功,则返回一个指向开辟好空间的指针。
如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
free函数
void free (void* ptr);
free函数用来释放动态开辟的内存。
如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。
malloc和free都声明在 stdlib.h 头文件中。
calloc
void* calloc (size_t num, size_t size);
函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
所以如何我们对申请的内存空间的内容要求初始化,那么可以很方便的使用calloc函数来完成任务。
realloc
realloc函数的出现让动态内存管理更加灵活。
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。
void* realloc (void* ptr, size_t size);
ptr 是要调整的内存地址
size 调整之后新大小
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
realloc在调整内存空间的是存在两种情况:
情况1:原有空间之后有足够大的空间
  • 当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
情况2:原有空间之后没有足够大的空间
  • 当是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。

常见动态内存错误

对NULL指针的解引用操作
对动态开辟的空间越界访问
对非动态内存空间使用free释放
使用free释放一块动态内存空间的一部分
对统一个动态内存空间释放多次
动态内存空间忘记释放(内存泄漏)

柔性数组

定义
C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。
柔型数组的特点
结构中的柔性数组成员前面必须至少一个其他成员。
sizeof 返回的这种结构大小不包括柔性数组的内存。
包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
柔型数组的使用
//代码1

int i = 0;
type_a p = (type_a)malloc(sizeof(type_a)+100*sizeof(int));
//业务处理
p->i = 100;
for(i=0; i<100; i++)
{
p->a[i] = i;
}
free§;

这样柔性数组成员a,相当于获得了100个整型元素的连续空间。
柔性数组的优势
第一个好处是:方便内存释放
第二个好处是:这样有利于访问速度.

C语言文件操作

为什么使用文件

什么是文件

磁盘上的文件是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

程序文件
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

文件的打开和关闭

文件指针
FILE* pf;//文件指针变量
通过文件指针变量能够找到与它关联的文件。
文件打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
//打开文件

FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

文件的顺序读写

文件的随机读写

fseek
根据文件指针的位置和偏移量来定位文件指针。
int fseek ( FILE * stream, long int offset, int origin );
ftell
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
rewind
让文件指针的位置回到文件的起始位置
void rewind ( FILE * stream );

文本文件和二进制文件

文本文件
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。

以ASCII字符的形式存储的文件就是文本文件。

二进制文件
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

文件读取结束的判定

牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
使用例子

文件缓冲区

程序环境和预处理

程序的翻译环境

组成一个程序的每个源文件通过编译过程分别转换成目标代码(object code)。
每个目标文件由链接器(linker)捆绑在一起,形成一个单一而完整的可执行程序。
链接器同时也会引入标准C函数库中任何被该程序所用到的函数,而且它可以搜索程序员个人的程序库,将其需要的函数也链接到程序中。

编译分几个步骤

1. 预处理 选项 gcc -E test.c -o test.i

预处理完成之后就停下来,预处理之后产生的结果都放在test.i文件中。

2. 编译 选项 gcc -S test.c

编译完成之后就停下来,结果保存在test.s中。

3. 汇编 gcc -c test.c

汇编完成之后就停下来,结果保存在test.o中。

程序的执行环境

1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手工安排,也可能是通过可执行代码置入只读内存来完成。
2. 程序的执行便开始。接着便调用main函数。
3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
4. 终止程序。正常终止main函数;也有可能是意外终止。

预定义符号介绍

FILE //进行编译的源文件

LINE //文件当前的行号
DATE //文件被编译的日期
TIME //文件被编译的时间
STDC //如果编译器遵循ANSI C,其值为1,否则未定义

预处理指令#define

语法:

#define name stuff

#define 后面不要加;加了会出现意想不到的错误
#define定义宏
#define name( parament-list ) stuff

其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。

参数列表的左括号必须与name紧邻。
如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
定义宏的时候要多加括号
#define的替换规则
1.在调宏的时候,首先对参数进行检查,看看是否包含任何#define定义的符号。如果是,它们被替换
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

宏和函数的定义

优势
宏比函数的规模和速度快
宏是类型无关的
劣势
1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2. 宏是没法调试的。
3. 宏由于类型无关,也就不够严谨。
4. 宏可能会带来运算符优先级的问题,导致程容易出现错。
宏的名字全大写,函数小写,以便区分

预处理操作符#和##的介绍

字符串的双引号会自动合并的
#把一个宏参数变成字符串
##将俩个符号合并成一个符号

命令定义

在命令的终端输入命令来定义某些参数的长度

预处理指令#include

“”表示先在项目所在的目录搜索,搜索不到在到VS的头文件目录搜索
<>直接去VS的头文件目录进行搜索
防止重复引用文件

条件编译

用来调试保留代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰深入学习计算机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值