各个C语言关键字的案例,C语言关键字(三)

这篇文件继续讲解

C

语言关键字

想问大家一个问题,什么是声明什么是定义?

举个例子:

A)int i

B)extern int i

(

关于

extern

,后面解释

)

哪个是定义?哪个是声明?或者都是定义或者都是声明?

什么是定义:

所谓的定义就是

(

编译器

)

创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名。但注意,这个名字一旦和这块内存匹配起来,它们就同生共死,终生不离不弃。并且这块内存的位置也不能被改变。一个变量或对象在一定的区域内(比如函数内,全局等)只能被定义一次,如果定义多次,编译器会提示你重复定义同一个变量或对象。

什么是声明:

有两重含义,如下:

第一重含义:告诉编译器,这个名字已经匹配到一块内存上了,(就比如你拿出结婚证告诉别人,我已经和别的内存块结婚了,请不要再勾搭我了)。

第二重含义:告诉编译器,我这个名字我先预定了,别的地方再也不能用它来作为变量名或对象名。(这个就有点耍赖,你拿着一个假的结婚证告诉别人,我已经结婚了,但是实际上,你还没有妹子,还没有分配内存空间)。

好,这样一解释,我们可以很清楚的判断

:A)

是定义;

B)

是声明。

那他们的区别也很清晰了。记住,

定义声明最重要的区别:定义创建了对象并为这个对象一块内存,而声明的时候是没有分配内存空间的。

1

,不需要记住的关键字

----auto

auto

:他太普通了,你就当它不存在吧。编译器在默认的缺省情况下,所有变量

都是

auto

的。

2

,最快的关键字

----

register

register

:这个关键字请求编译器尽可能的将变量存在

CPU

内部寄存器中而不是通过内

存寻址访问以提高效率。注意是尽可能,不是绝对。你想想,一个

CPU

的寄存器也就那么

几个或几十个,你要是定义了很多很多

register

变量,它累死也可能不能全部把这些变量放

入寄存器吧,轮也可能轮不到你。

2.1

,皇帝(

CPU

)身边的小太监

----

寄存器

cpu

类比成为一个皇帝,那

register

就是皇帝身边的小太监了,不知道大家见过太监没有,我们看各种宫斗剧的时候,太监是唯命是从,只要皇帝叫做什么,太监马上就去做,速度之快令人瞠目结舌,也就是因为速度快,所以皇帝才配有太监,而且不止有一个太监,太监就像一个文件中转站,把下面人的折子拿给皇帝批阅。

所以太监的特点是

1

、响应速度快

2

、数量少,只给皇帝工作

3

、价格贵

2.2

,使用

register

修饰符的注意点

虽然寄存器的速度非常快,但是使用

register

修饰符也有些限制的:

register

变量必须是能被

CPU

寄存器所接受的类型。意味着

register

变量必须是一个单个的值,并且其长度应小于或等于整型的长度。

而且

register

变量可能不存放在内存中,所以不能用取址运算符

“&”

来获取

register

变量的地址。

3

、确定位置的关键字

----static

3.1

static

修饰变量

修饰静态全局变量:作用域仅限制于被定义的文件中,其他文件即使用

extern

声明也没有办法使用,作用域从定义之处开始,到文件结尾处,在定义之前的代码不能使用。本文件可以在之前加

extern

,不过这样还不如直接在顶端定义。

静态全局变量:在函数体里面定义的,就只能在函数里面使用了,由于

static

定义的变量存在静态区,改函数执行结束,变量的值还是存在,不会销毁,下次该函数调用时,

static

定义的变量值是上一次调用时候的值。

3.2

static

修饰函数

在函数前面加

static

表示函数成为静态函数,表示该函数的作用域仅限于定义处到文件结尾。如果全局函数有一个函数名字和静态函数一样的名字,编译器不会报错,使用本文件的静态函数运行。

#include

static

int

j;

void

func1

(

void

)

{

static

int

i

=

;

i

++

;

printf(

"i = %d\n"

, i);

}

void

func2

(

void

)

{

j

=

;

j

++

;

printf(

"j = %d\n"

, j);

}

int

main

(

int

argc,

char

*

argv[])

{

int

k

=

;

for

(k

=

; k

<

10

; k

++

)

{

func1();

func2();

printf(

"\n"

);

}

return

;

}

大家运行上面代码加深下对

static

的理解

4

、大喇叭关键字

----extern

上面有一个例子已经说到了

extern,extern

就像一个大喇叭一样,他不分配内存,就是不讨老婆,但是总是跟别人说,谁谁娶媳妇了,这个标识符就定义了,这个函数被定义了,如此如此,不过这个大喇叭非常有用,比如他可以跟编译器说,这个家伙已经讨老婆了,你可以用他生孩子了,就不要再让他二婚了。

既然

extern

不能给别人发结婚证,那么下面这个

extern int i = 10;

是否有问题?

不能发结婚证,就是不能分配内储存,没有内存怎么把

10

存下来?所以肯定是错的。

5

、让

cpu

最累的关键字

----volitile

volitile

这个关键字让

cpu

非常累,每次运行到他的位置,都要去内存重新确定他的值,在中断的使用的变量最好用这个关键字修饰,因为中断的变量你不知道什么时候会被改变,

volatile

的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。说白了就是不能让

cpu

偷懒,所以说是类似老大

CPU

了。

6

、只能读的关键字

----const

const

可以理解为别人只能来读我的值,不能改变我,有的人写代码加上这个就是担心自己的值被改变,比如

const int i =5;

下一次,

i =6;

这就是有问题的,

i

的值已经确定了,就像

define

一样(

不过

define

不是关键字

)。

/*************************************************************************

> File Name: const.c

> Author:

> Mail:

> Created Time: Mon 29 Oct 2018 02:33:19 PM CST

************************************************************************/

#include

#define M 3

const

int

N

=

5

;

void

main

(

void

)

{

printf(

"%p\n"

,

&

N);

int

i

=

M;

int

j

=

N;

printf(

"%p\n"

,

&

N);

int

x

=

M;

int

y

=

N;

printf(

"%p %p %p %p\n"

,

&

i,

&

j,

&

x,

&

y);

printf(

"%d %d %d %d\n"

,i,j,x,y);

}

7

、不色不空的关键字

----void

大家可以看看

void

void*

,谁是色,谁是空呢?

void

表示这个是空的,什么都没有,比如

void i;

我们定义一个空的

i

,这就有问题了,这个

i

编译器到底要不要给他分配空间呢?就是这样的情况,编译器报错了,你搞什么飞机给我一个空的东西还想让我给你讨老婆。

但是

void

不一样,

void

*

表示所有类型的指针,这就是色啊,女人都想入非非。

说明:

既然提供了

void

的这两种用法,就去运用。即函数没返回值就将其返回值类型写为

void

,函数没有形参就将其形参写为

void

。不了解编译器默认操作时,不要依赖。即使了解其默认操作,也别依赖,因为肯定有人不了解的,这样别人就看不懂你的代码了。

大家看看这个是否正确

add(int a,int b)

{

return (a+b);

}

下面两个函数就是用

void*

作为返回值

memcpy

原型:

extern void *memcpy(void *dest, void *src, unsigned int count);

用法:

#include

功能:由

src

所指内存区域复制

count

个字节到

dest

所指内存区域。

说明:

src

dest

所指内存区域不能重叠,函数返回指向

dest

的指针。

注意:与

strcpy

相比,

memcpy

并不是遇到

'\0'

就结束,而是一定会拷贝完

n

个字节。

memset

原型:

extern void *memset(void *buffer, int c, int count);

用法:

#include

功能:把

buffer

所指内存区域的前

count

个字节设置成字符

c

说明:返回指向

buffer

的指针。

8

return

关键字

return

关键字终止一个函数并返回一个值。

#include

"stdio.h"

add(

int

a,

int

b)

{

return

(a

+

b);

}

char

*

str(

void

)

{

char

*

strc

=

"This is c\n"

;

return

strc;

}

main(

void

)

{

printf(

"%d\n"

,add(

1

,

4

));

printf(

"%s\n"

,str);

return

;

}

看看上面这个函数的输出,会有陷阱的

9

、柔性数组

讲了很多关键字,现在讨论一个酷的东西,以后也会经常用到,柔性数组是可以自由变化长度的数组,对开发上来说是非常有用的。

C99

中,结构体的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构体的柔性数组成员前面必须至少一个其他成员。

#include

typedef

struct

_SoftArray{

int

len;

int

array[];

}SoftArray;

int

main

()

{

int

len

=

10

;

printf(

"The struct's size is %d\n"

,

sizeof

(SoftArray));

}

viewspace-2221196

我们可以看出,

_SoftArray

结构体的大小是

4

,显然,在

32

位操作系统下一个

int

型变量大小刚好为

4

,也就说结构体中的数组没有占用内存。为什么会没有占用内存,我们平时用数组时不时都要明确指明数组大小的吗?但这里却可以编译通过呢?这就是我们常说的动态数组,也就是柔性数组。

#include

#include

typedef

struct

_SoftArray{

int

len;

int

array[];

}SoftArray;

int

main

()

{

int

len

=

10

,i

=

;

SoftArray

*

p

=

(SoftArray

*

)malloc(

sizeof

(SoftArray)

+sizeof

(

int

)

*

len);

p

->

len

=

len;

for

(i

=

;i

<

p

->

len;i

++

)

{

p

->

array[i]

=

i

+

1

;

}

for

(i

=

;i

<

p

->

len;i

++

)

{

printf(

"%d\n"

,p

->

array[i]);

}

free(p);

return

;

}

viewspace-2221196

这代码的作用是用柔性数组动态创建数组并输出数组内容,这里我就直接解释解释这两句代码

SoftArray

*

p

=

(SoftArray

*

)malloc(

sizeof

(SoftArray)

+

sizeof

(

int

)

*

10

);

p

->

len

=

10

;

第一句,主要是根据你要定义的数组长度和数据类型以及柔性数组本身的大小来开辟一块内存空间给柔性数组,第二个是定义

len

的长度,便于确定循环打印输出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值