文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C语言关键字(三)

2023-06-03 09:39

关注

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

所以太监的特点是

响应速度快

数量少,只给皇帝工作

价格贵

 

 

2.2,使用register修饰符的注意点

 

虽然寄存器的速度非常快,但是使用register 修饰符也有些限制的:register 变量必须是能被CPU 寄存器所接受的类型。意味着register 变量必须是一个单个的值,并且其长度应小于或等于整型的长度。而且register 变量可能不存放在内存中,所以不能用取址运算符“&”来获取register 变量的地址。

3、确定位置的关键字----static

1、static 修饰变量

修饰静态全局变量:作用域仅限制于被定义的文件中,其他文件即使用extern声明也没有办法使用,作用域从定义之处开始,到文件结尾处,在定义之前的代码不能使用。本文件可以在之前加extern ,不过这样还不如直接在顶端定义。

 

静态全局变量:在函数体里面定义的,就只能在函数里面使用了,由于static定义的变量存在静态区,改函数执行结束,变量的值还是存在,不会销毁,下次该函数调用时,static定义的变量值是上一次调用时候的值。

2、static修饰函数

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

#include<stdio.h>

 

staticintj;

 

voidfunc1(void)

{

     staticint=;

     i++;

     printf("i = %d\n", i);

}

 

voidfunc2(void)

{

     j =;

     j++;

     printf("j = %d\n", j);

}

 

intmain(intargc, char*argv[])

{

     int=;

     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不是关键字)。

                        

#include<stdio.h>       

#define M 3             

constint=5;        

                        

voidmain(void)        

{                       

    printf("%p\n",&N);

    int=M;          

    int=N;          

    printf("%p\n",&N);                                                                                                

    int=M;          

    int=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的指针。

8return 关键字

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

#include"stdio.h"

 

add(inta,intb)

{

    return(a+b);

}

 

char*str(void)

{

    char*strc ="This is c\n";

    returnstrc;

}

 

main(void)

{

    printf("%d\n",add(1,4));

    printf("%s\n",str);

    return;

}

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

9、柔性数组

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

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

#include<stdio.h>

typedefstruct_SoftArray{

    intlen;

    intarray[];

}SoftArray;

 

intmain()

{

    intlen =10;

 

    printf("The struct's size is %d\n",sizeof(SoftArray));

}

C语言关键字(三)

我们可以看出,_SoftArray结构体的大小是4,显然,在32位操作系统下一个int型变量大小刚好为4,也就说结构体中的数组没有占用内存。为什么会没有占用内存,我们平时用数组时不时都要明确指明数组大小的吗?但这里却可以编译通过呢?这就是我们常说的动态数组,也就是柔性数组。

#include<stdio.h>

#include<malloc.h>

typedefstruct_SoftArray{

intlen;

intarray[];

}SoftArray;

intmain()

{

    intlen=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;

}

C语言关键字(三)

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

   SoftArray*=(SoftArray*)malloc(sizeof(SoftArray) +sizeof(int*10);

     p->len =10;

第一句,主要是根据你要定义的数组长度和数据类型以及柔性数组本身的大小来开辟一块内存空间给柔性数组,第二个是定义len的长度,便于确定循环打印输出

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯