分享

「C语言重点难点精讲」关键字精讲2

 启云_9137 2021-11-29

九:goto关键字

第一: goto基本控制逻辑或者基本语法如下

int main() { int i = 0; START: printf('[%d]goto running ... \n', i); Sleep(1000); ++i; if (i < 10){ goto START; } printf('goto end ... \n'); return 0; }

文章图片1

十:void关键字

第一: void是不能用来定义变量的。因为定义变量的本质就是开辟内存空间,而void作为空类型是不应该开辟空间的,即使开辟了空间,也仅仅作为一个占位符来看待,所以这种行为直接就会被编译器禁止

第二: 首先说明一点,在C语言中函数是可以不带返回值的,返回类型为整型

文章图片2

的确在有些场景中我们是不需要函数的返回值的,但如果采用上面的那种方式书写,很容易产生阅读上的歧义,因此如果函数不想让其返回,可以用void,这里一定要将其理解为一种占位符,它是告知用户和编译器的

文章图片3

第二: 在如下情形中,编译器是不会报错的,因此会有很大的安全隐患

文章图片4

而如果限制void后,编译器将会报警。因此void可以充当函数的形参列表,用于告知编译器和用户该函数不需要传入参数

文章图片5

第四: void的确不可以定义变量,但是void*可以,因为指针变量的大小是明确的(Windows32位下为4个字节大小)

void* p=nullptr;

第五: void可以被任何类型的指针接受,void也可以接受任意指针类型

int main() { void p = NULL; int x = NULL; double y = NULL; p = x;//void接受int p = y;//void接受double* }

  • 尤其注意 void*也可以接受任意指针类型,这一点通常用作一些通用接口的设计

第六: 我们知道,普通类型的指针可以进行位运算

int* p=NULL; p++; p--;

而对于void*呢?要视平台而定,一般VS下不可以,Linux下可以(Linux认为void是1)

十一:return关键字

第一return不可以返回指向“栈内存”的指针,因为在函数体结束时会被自动销毁

因此下面的语句会出现乱码

char show() { char str[] = 'hello world'; return str; } int main() { char s = show(); printf('%s\n', s); return 0; }

文章图片6

第二: 函数的返回值,通过寄存器的方式,返回给函数的调用方(注意区别上面,上面不能那样做,因为那是指向栈的指针)

int GetData() { int x = 0x11223344; printf('running\n'); return x; } int main() { int y = GetData(); printf('return value:%x\n', y); return 0; }

文章图片7

return x对应的汇编代码为:

文章图片8

十二:const关键字

第一: const修饰的变量不可以直接被修改

const int a=10; a=20;//错误

但间接可以修改

int main() { const int a = 10; int p = &a; printf('change before:%d\n', a); p = 20; printf('change after:%d\n', a); return 0; }

那么既然这样其意义何在呢?其实const修饰变量主要有下面两个目的

  1. 让编译器进行直接修改式检查
  2. 告诉其他人这个变量不要改动,属于“自描述”含义
文章图片9

真正意义上的不可修改如C语言中的常量字符串

int main() { char str = 'hello world\n';//常量字符串 str ='E'; return 0; }

文章图片10

第二: const int i 和int const i是等价的

第三: const修饰的变量同样不能作为数组定义的一部分(标准C不可以,但是在Linux可以)

int main() { const int n = 100; int arr[n];//错误 return 0; }

第四: const在定义时必须初始化

第五: 建立只读数组可以这样写

int const a[5]={1,2,3,4,5};const int a[5]={1,2,3,4,5};

第六 :const放在谁后面就修饰谁,因此它与指针的关系如下

①:const int i 与int const i等价

其中i是指针,const修饰了int,表示指针可以变化,但是指针指向内容不能被修改

文章图片11

②:int* const i

const修饰的是指针,所以指针不可变,但是指向的内容可变

文章图片12

③:const int* const i=&a

表示指针不可以变,指向的内容也不可以变

文章图片13

第七: const 也可以用来修饰函数参数,表明不可更改

void show(const int p)//防止指针指向内容被修改 { printf('value:%d\n', p); p = 20;//非法操作 } int main() { int a = 10; int* p = &a; show(p); }

十三:volatile关键字

有关volatile关键字的作用在下面这篇文章中有详细介绍,请移步

  • Linux系统编程34:进程信号之可重入函数,volatile关键字的作用和SIGHLD

volatile关键字的作用:volatile将保持内存的可见性,一个变量一旦被volatile修饰,那么系统总是会从内存中读取数据,而不是从寄存器

需要注意const和volatile的区别,两者并不矛盾

  • const要求你不要进行写入
  • volatile意思是你读的时候每次要从内存读

十四:extern关键字

extern关键字这里就多说了,非常简单

十五:struct关键字

第一: struct基本介绍

定义

文章图片14

初始化(不能初始化后整体赋值)

文章图片15
文章图片16

成员访问

文章图片17

结构体传参

文章图片18

第二: 在Linux中空结构体的大小为0

第三: 柔性数组

我们知道C语言中是不能有这样的操作的,就是用变量对数组进行初始化

int main() { int i=0; scanf('%d',&i); int arr[i]; }

在C语言中如果要完成动态数组,可以借助柔性数组。使用柔性数组时,我们采用结构体的方式,将一个数组作为结构体成员放置于其中,但注意该数组不初始化,什么都不写

文章图片19

在上述结构体中,有两个结构体变量,数组似乎不占空间,但其实不然。实则,该结构体将其所占空间划分为两部分,一部分就是那个整形,一部分用于动态开辟,以此满足数组的动态变化

文章图片20

既然是柔性,那就可以修改,使用realloc修改

文章图片21

十六:Union关键字

第一: Union是什么

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间,联合体内所有成员的起始地址都是一样的,每个成员都认为它是联合体的第一个成员

文章图片22

第二: 根据内存地址分布,如下,b永远定义在相对于a的低地址处

union Un { int a; int b; };

根据这一性质我们可以利用联合体来判断机器是大端机还是小端机,如下

union Un { int a; char b; }; int main() { union Un u; u.a = 1; if (u.b == 1){ printf('小端机\n'); } else { printf('大端机\n'); } return 0; }

文章图片23

这是因为

文章图片24

十七:enum关键字

enum用于枚举一堆常量,就像Excel中的数据有效性,它规定了数据的取值类型,比如说男性它只有男或女

定义

文章图片25

enum color是枚举类型,括号中的内容是枚举类型的可能取值,也叫做枚举常量。这些可能取值实际上是有值的,默认是从0开始的

文章图片26

当然是可以修改的

文章图片27

枚举的这样的写法其实和宏的写法在代码的逻辑上是相似的

文章图片28

十八:typedef关键字

第一: typedef的作用就是为类型重新命名

typedef unsigned int uint; int main() { uint a = 10; return 0; }

文章图片29

typedef 经常会在结构体重命名里

typedef struct stu { int a; int b; }Student; int main() { Student student1; }

第二: 大家一定要对typedef理解到位,如下

int main() { int* a, b; //a是指针类型 //b是整形 }

typedef从某种方面可以理解一种全新的类型,因此下面的*就不存在和谁结合的问题了

typedef int intp; int main() { int_p a, b; //a是指针类型 //b也是指针类型 }

文章图片30

而对于#define而言它就是一种文本替换了,因此

#define intp int int main() { int_p a, b; //a是指针类型 //b是整形 }

文章图片31

第三:使用typedef定义后的新类型,不能配合其他关键字使用

#define INTDE int typedef int INTTY; int main() { unsigned INTDE a;//正确 unsigned INTTY b;//错误 }

总结

(1)关键字分类

数据类型关键字

  • char
  • short
  • int
  • long
  • signed
  • unsigned
  • float
  • double
  • struct
  • union
  • enum
  • void

控制语句关键字

1:循环控制

  • for
  • do
  • while
  • break
  • continue

2:条件语句

  • if
  • else
  • goto

3:开关语句

  • switch
  • case
  • default

4:返回语句

  • return

存储类型关键字

  • auto
  • extern
  • register
  • static
  • typedef

这里需要补充一点:使用typedef时不能同时出现多个存储关键字

typedef static int//错误 typedef register int//错误

其他关键字

  • const
  • sizeof
  • volatile

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多