2675字带你进阶C语言中的关键字

C语言进阶之C语言关键字

关键字总结.png

基本数据类型

1.数据类型

  • 数据类型可以理解为固定内存大小的别名(例如,在C语言中int数据类型代表了4个字节的内存)
  • 数据类型是可以创建变量的模板

数据类型的本质就是固定字节别名

2.变量

  • 变量是一段实际连续存储空间的别名
  • 程序中通过变量来申请并命名存储空间
  • 通过变量的名字可以使用存储空间

auto,register,static分析(属性关键字)

  • C语言中的变量可以有自己的属性
  • 在定义变量得时候可以加上“属性”关键字
  • “属性”关键字指明变量具有特有意义(例如static修饰的关键字,具有特殊的意义是使修饰的变量的生命周期与程序的生命周期同步)。

auto(在程序的栈上面)

  • auto即C语言中局部变量得默认值。
  • 编译器默认所有的局部变量都是auto属性的

最佳示例

写一个简单的打印数字的程序

#include<stdio.h>
int main(){
        auto  int a =10;
          printf("%d",a);
}

你会发现auto 似乎并没有什么软用

static(在内存的静态区里面的变量)

  • static修饰的全局变量作用域只是申明的文件中

最佳实例一

新建两个.c文件,分别为test.ctest2.c

test.c

#include<stdio.h>
extern int test2_g;
int main()
{
    printf("%d",test2_g);
    return 0;
}

test2.c

static int test2_g=1;

我们尝试用用gcc编译两个.c文件,会报一个未定义应用的错误。如果,我们把test2.c中的static去掉,程序就和我们预想的结果相同。也就是说static让变量test2_g私有化了。在C语言面向对象编程中,可以完全将它作为private来用。

如果我们需要访问这个变量,也是有办法的。正如其他面向对象语言中一样,我们可以写一个get方法来获取它的值。我们修改test2.c这个文件。

static int test2_g=1;
int get_test2_g()
{
    return test2_g;
}

再修改test.c这个文件

#include<stdio.h>
extern int  get_test2_g();
int main()
{
    printf("%d", get_test2_g());
    return 0;
}

两句话总结static

  1. static存在内存的静态存储区,有着和程序一样长的生命周期。
  2. static修饰的函数作用域只是申明的文件中(也就是说只能在一个C文件中)。相当于java中的private

register(用在非常讲究性能的实时系统中,通常嵌入式工程师才需要)

  • register关键字指明将变量存储于寄存器中
  • register只是请求寄存器变量,但不一定成功

注意:

register变量得必须是CPU寄存器可以接受的值
不能用&运算符获取register变量的地址

总结

  1. auto变量存储在程序的栈中,默认属性只能是局部变量
  2. static变量存储在程序的静态区
  3. register变量存储请求存储于CPU寄存器中只能是局部变量
  • 全局变量与静态变量在程序的全局&&静态数据区

if,switch,do,while,for分析

分支语句

bool数据类型

C语言中默认是没有bool类型(标准为C99),实际项目开发又十分需要bool类型我们可以自己创建一种新的数据类型。

typdef enum _bool{
    FALSE,
    TRUE
}BOOL;

使用

BOOL a;
if(a)
{
}

if注意点

  • bool型变量应该直接出现于条件中,不要进行比较。

    • 例如if(True==True)这样的写法。
  • 普通变量和0(或其他常数)比较时,0值应该出现在比较符号的左边(经验!!!)

    • 举例子

      在项目开发中我们需要一个变量与常数比较,例如

      #include<stdio.h>
      int main(){
              int a=90;
              if (a==100){
                //todo
              }
      }
      
      

      如果我们手贱写将a==100写成a=100

      #include<stdio.h>
      int main(){
              int a=90;
              if (a=100){
                //todo
              }
      }
      

      很显然的是编译仍然通过,但是程序逻辑是不对的.

      如果我们在对常数的比较中,采用

      #include<stdio.h>
      int main(){
              int a=90;
              if (100==a){
                //todo
              }
      }
      

      这样的写法,手抖少写个等号又何妨。

  • float型变量不能直接进行0值比较,需要定义精度

  • 因为对于不同的系统,float的精度不一样,所以,是有必要进行这种比较的

    #define ESPINON 0.0000 0001
    float f=0.0f;//如果不定义精度,很有可能出错
    
    if((-ESPINON<=f) && (f<=ESPINON))
    {
    }
    

switch注意事项

  • case语句中的值只能是整型或字符型
  • case排列顺序的分析
    • 按字母或者数字顺序排列各条语句
    • 正常情况放前面,异常情况放在后面
    • default语句只能用于处理真正的默认情况
    • 单值
  • 每个case语句分支必须有break,否则分支重叠。

分支语句的总结

  • if按片,switch对每个离散值来判断
  • if可以替代switch,但是switch不能取代if
  • switch在多分支里,比较简单

循环语句

  • 循环语句的基本工作方式
    • 通过条件表达式判定是否执行循环体
    • 条件表达式遵循if语句表达式的原则
  • do,while,for的区别
    • do先执行后判断,也就是说必须执行一次
    • while语句先判断后执行,循环体可能不执行
    • for语句先判断后执行,相比while更简洁
      if(n>0)
      {
          do{
              ret +=n--;
          }while(n);              
      
      }
      
  • break和continue的区别
    • break表示终止循环的执行
    • continue终止本次循环

switch能否用continue?
不能

do和break的妙用(一般程序设计分析)

do{
    //todo
}while(0)//作为一种代码块的作用
free(p);

goto,void,extern,sizeof分析

goto

  • 你一定是有特殊技巧,才用的吧

void的意义

  • 如果函数没有返回值,那么应该将其声明为void型
  • 如果没有参数,应该声明其参数为void

表示无

void指针的意义

  • C语言规定只有相同类型的指针才可以相互赋值

  • void*指针作为左值用于“接收”任意类型的指针

  • void*指针作为右值赋值给其他指针时需要强制类型转换

    • 大名鼎鼎的malloc就是void *类型的

extern中隐藏的意义

  • extern 用于声明外部定义的变量和函数

  • extern 用于“告诉”编译器用C的方式编译,这里有一篇更加深入的文章extern "c"用法解析

    • extern "C"
      {
        //todo
      }
      

      为什么要这样做呢?因为有些编译器在编译的时候,自以为是的优化,导致程序无法正常运行。

      还有就是在CPP中用C代码

sizeof

  • sizeof是编译器的内置指示值,不是函数

    • 为什么呢?我是如何知道的呢?通过三点

      1. 一般系统函数在C语言预处理的时候,都会通过extern引入到预处理文件,然而sizeof并没有。

      2. 你见过C语言有可以接受数据类型的数据类型么?

      3. //上下一样的,所以sizeof这个叼毛不是函数
        sizeof(a);
        sizeof a;
        
  • sizeof用于“计算”相应的实体所占的内存大小

  • sizeof的值在编译期就已经确定

const和valatile分析

const(是可以修改的)

  • 在C语言中const修饰的变量时只读的,其本质还是变量
  • const修饰的变量会在内存占用空间
  • 本质上const只对编译器有用,在运行时无用
  • 在C语言中const修饰的数组是只读的
  • const修饰的数组空间不可被改变(编译器的过,通过指针不能改变,gcc就不行)

const修饰指针

const int* p; //p可变,p指向的内容不可变
int const* p;//p可变,p指向的内容不可变
int* const p;//p不可变,p指向的内容可变
const int* const p;//p和p指向的内容都不可变

最佳实例

**口诀:左数右指 **
指针符号在const左边的时候指针所指向的数字不能发生改变,右边的时候

左数
void main()
{
    int i=0;
     int const * p=&i;
    * p=3;
}
右指
#include<stdio.h>
void main()
{
    int i=0;
     int * const p=&i;
    * p=3;
    p=NULL;
}

const修饰函数参数和返回值

  • const修饰函数参数表示在函数体内不希望改变参数的值
  • const修饰的函数返回值表示返回值不可改变,多用于返回指针
    最佳实例
#include<stdio.h>
const int * func()
{
    int i=0;
    i++;
    return & i;
}
int main()
{
    const int * q=func();
    printf("%d\n",*q);
}

valatile

  • volatile可理解为“编译器警告指示字”
  • volatile用于告诉编译器必须每次去内存中取变量值
  • volatile主要修饰可能被多个线程访问的变量(有没有java 的味道)
  • volatile也可以修饰可能被未知因数更改的变量

struct和union分析

由结构体产生柔性数组

  • 柔性数组既数组大小待定的数组
  • C语言中结构体的最后一个元素可以是大小未知的数组
  • C语言中可以由结构体产生柔性数组

柔性数组实例

struct SoftArray{
    int len;
    int array[];
};

柔性数组Dome

#include<stdio.h>
#include<malloc.h>
typedef struct _SoftArray{
    int len;
    int array[];
}SoftArray;
int main()
{
    int len=10,i=0;
    SoftArray *p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*len);
    p->len=len;
    for(i=0;i<len;i++)
    {
        p->array[i]=i+1;
    }
    for(i=0;i<len;i++)
    {
        printf("%d\n",p->array[i]);
    }
    
    return 0;
}

使用柔性数组创建斐波那契数列

#include<stdio.h>
#include<malloc.h>
typedef struct _softArray{
  int len;
  int array[];
}SoftArray;
SoftArray * creat_Array(int size)
{
    SoftArray *p=NULL;
    if(size>0)
    {
    p=(SoftArray*)malloc(sizeof(SoftArray)+sizeof(int)*size);
    p->len=size;
    }
    return p;
}
void del_Array(SoftArray * p)
{
    free(p);
}
void create_Fibonacci(SoftArray* p)
{
    int i=0;
    if(NULL!=p)
    {
        if(1==p->len)
        {
            p->array[0]=1;
        }else
        {
            p->array[0]=1;
            p->array[1]=1;
            if(p->len>2)

            {
                for(i=2;i<p->len;i++)

                {
                    p->array[i]=p->array[i-1]+p->array[i-2];
                    }
                }
        }

    }
}
int main()
{
    int i=0;
    SoftArray * my=creat_Array(10);
    create_Fibonacci(my);
    for(i=0;i<10;i++)
    {
        printf("%d\n",my->array[i]);
    }
    
    del_Array(my);
    
    return 0;
}

记得释放数组(和JavaSE不同)

union和struct的区别

  • struct 中的每个域在内存中都独立分配空间
  • union只分配最大域的内存空间

区别的最佳实例

#include<stdio.h>
#include<malloc.h>
struct A{
    int a;
    int b;
};
union B{
    int a;
    int b;
};
int main()
{
    printf("struct is %d\n",sizeof(struct A));//结果为8
    printf("union is %d\n",sizeof(union B));//结果为4
    return 0;
}
  • union受系统大小端的影响

    • 学过操作系统的人都知道系统有大小端之分,一般来讲我们的PC,迫于某大厂,所以是小端的

      测试电脑是大端还是小端的程序

      #include<stdio.h>
      int checkSys()
      {
          union check{
              int i;
              char c;
          }cc;
          cc.i=1;
          return cc.c;
      }
      int main()
      {
        if(1==checkSys())
            printf("小端\n");
          else
            printf("大端\n");
          return 0;
      }
      

      上面程序的原理是:

      因为union分配最大数据类型的空间,如果是大端模式的话,高地址先被分配到,被赋值为1,我们调用cc.c 取的是低地址,应当是0.。小端的话反之则反。

枚举类型

  • enum是一种自定义类型
  • enum默认常量在前一个的基础上依次加一
  • enum类型的变量只能取定义时的离散值
enum Color{
    GREEN,
    RED=2,
    BLUE
};

enum 默认的第一个是0,也就是说上面代码段中GREEN为0,BLUE为3

枚举类型与#define的区别

#include <stdio.h>
#define YELLOW 1
int main() {
    enum Color{
        GREEN,
        RED
    };
    if (YELLOW ==GREEN){

    }
    return 0;
}

我们用gcc -E 处理一下这个程序,然后会发现原本的程序变成

....
int main() {
    enum Color{
        GREEN,
        RED
    };
    if (1 ==GREEN){

    }
    return 0;
}



区别全在程序里,程序本身没有意义

typedef

  • typedef用于给一个已经存在的数据类型重命名
  • typedef并没有产生新的类型
  • typedef从定义的类型不能进行unsigned和signed扩展
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容