【C语言】第一章:初识C语言(四)

目录

十一、关键词

常见关键词总结及分类

1.类型

2.循环:

3.选择分支:

4.其他

(二)关键词register

(三)关键词typedef

(四)关键词static

1修饰局部变量

2.修饰全局变量

3.static修饰函数

十二、#define定义常量和宏

(一)#define定义常量

(二)宏

总结


十一、关键词

  • 常见关键词总结及分类

C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。

这是常见的关键字,接下来我们对其进行分类一下。

1.类型

Char,用于表示字符类型的数据

Int,用于表示整数类型的数据

Short,用于表示短整数类型的数据

Long,用于表示长整数类型的数据

Float,用于表示单精度浮点数类型的数据

Double,用于表示双精度浮点数类型的数据

Signed,用于修饰整数类型,表示有符号的数据。默认情况下,整数类型是带符号的,因此可以省略signed关键字。

Unsigned,用于修饰整数类型,表示无符号的数据。使用unsigned关键字可以扩展正数的范围。

Static,用于声明具有静态存储持续时间的变量或函数。静态变量在程序的整个生命周期内保持其值,并且仅在声明它们的作用域内可见。静态函数仅在声明它们的源文件中可见。

void ,用于表示没有返回值或不接受任何参数的函数。也可以用于声明指针类型,表示未指定具体类型的指针。

const ,用于声明常量,表示其值在初始化后不能被修改。被const修饰的变量在程序执行期间是只读的。

enum ,用于定义枚举类型,枚举类型是一组命名的整数常量集合。枚举常量按顺序排列,默认从0开始递增。

union ,用于创建一种特殊的数据类型,它可以在相同的存储空间内存储不同类型的数据。多个成员共享同一块内存,但每次只能使用一个成员。

struct ,用于创建自定义的复合数据类型,可以存储多个不同类型的数据。struct关键字定义了一种包含多个成员变量的结构。

typedef ,用于为已存在的数据类型创建一个新的类型别名。通过typedef可以简化复杂的类型声明,也可以增加代码的可读性和可维护性。

2.循环:

循环是用于重复执行一段代码的结构。在C语言中,常见的循环结构有for、while和do-while三种形式。

break:

break 用于在循环或者switch语句中强制跳出当前循环或者switch语句,继续执行循环或者switch后面的代码。

continue:

continue 用于在循环中跳过当前迭代,立即进行下一次迭代。它会终止当前迭代中剩余的代码,并开始下一次迭代。

do-while:

do-while 是一种后测试循环,即先执行循环体中的代码,然后再判断循环条件是否满足。如果条件满足,则继续执行下一次循环。

while:

while 是一种先测试循环,即先判断循环条件是否满足,如果条件满足,则执行循环体中的代码。如果条件不满足,则跳过循环。

for:

for 是一种常用的循环结构,它由初始化表达式、循环条件和循环后更新表达式组成。在每次循环迭代开始前,会先执行初始化表达式,然后判断循环条件是否满足,如果条件满足,则执行循环体中的代码,并在每次循环结束后执行更新表达式。

3.选择分支:

选择分支是用于根据条件来决定程序执行路径的结构。在C语言中,常见的选择分支结构有if-else和switch-case两种形式。

if:

if 是一种条件语句,它用于根据给定的条件判断是否执行特定的代码块。如果条件满足,则执行if后面的代码块,否则跳过。

else:

else 是与if搭配使用的一种关键字,用于在条件不满足时执行备选的代码块。当if的条件不满足时,会执行else后面的代码块。

switch:

switch 是一种多分支选择语句,根据表达式的值选择执行不同的代码块。通过switch关键字和后面的表达式,可以将控制流转移到匹配的case标签处。

case:

case 用于在switch语句中指定不同的情况。每个case标签对应一种可能的取值,如果表达式的值与某个case标签相匹配,则执行该case下对应的代码块。

break:

在switch语句中,break 用于跳出switch结构,终止代码的执行。如果省略了break语句,则会继续执行后续case中的代码。

default:

default 是在switch语句中可选的标签,用于指定当没有任何case标签匹配时执行的默认代码块。

goto:

goto 是一种无条件的分支语句,用于直接跳转到程序中的标签处。goto语句可以用来跳过特定的代码块或者在程序中实现复杂的控制流程,但滥用会导致代码难以理解和维护,因此应谨慎使用。

4.其他

extern 声明外部符号

register 寄存器

return 函数返回

sizeof 计算所占内存大小

volatile 后文详细介绍

(二)关键词register

register是C语言中的一个关键词,用于建议编译器将变量存储在寄存器中,以提高效率。需要注意的是,register关键词仅仅是对编译器的建议,具体是否将变量存储在寄存器中取决于编译器的实现。

  

在计算机中,数据可以存储在不同的存储介质中,而这些存储介质的选择与其造价、存储大小和访问速度有关。一般来说,存储器的层次结构由下到上依次包括硬盘、内存、高速缓存和寄存器。存储介质的价格逐渐升高,存储容量逐渐减小,但访问速度也越快。

CPU(中央处理器)起到了控制和执行计算机指令的作用。在早期,CPU从内存中获取数据,因为当时CPU的速度相对较慢,而内存的速度相对较快,两者之间的匹配是比较合理的。然而,随着CPU速度的快速增加,内存速度提升的速度并没有跟上,这就导致了CPU无法充分发挥其性能,即使再快的CPU也会被内存限制。为了解决这个问题,人们设计了更快的高速缓存和寄存器。虽然它们的存储容量较小,但由于访问速度非常快,可以满足CPU的要求。这样,我们就可以让CPU的数据从寄存器中获取,剩余的数据从高速缓存中获取,高速缓存再从内存中获取,最后内存再从硬盘中获取。这种层次结构的设计能够有效提高计算机的数据处理能力。

int main()
{
       register int a = 0;
       return 0;
}

回到我们对register关键词的讨论,使用register关键词可以建议编译器将变量存储在寄存器中,以便在程序执行时提高效率。需要注意的是,具体是否将变量存储在寄存器中取决于编译器的实现。现代的编译器通常会根据程序的运行情况和底层系统的特性来做出最优的决策,因此在大多数情况下,手动使用register关键词并不能带来显著的性能提升。

(三)关键词typedef

Typedef直译是类型定义,但是此处应该理解为类型重命名。

接下来用一段代码加以理解。

typedef unsigned int uint;

int main()
{
    uint a = 10;
    uint b = 5;

    printf("a: %u\n", a);
    printf("b: %u\n", b);

    return 0;
}

这个示例中,我们定义了一个uint类型,它是unsigned int类型的别名。通过使用typedef将unsigned int重命名为uint,我们可以在程序中使用uint作为变量类型。这样做的好处是,可以使代码更加清晰、易读,并且可以方便地更改底层数据类型,而无需在整个代码中进行大量修改。

(四)关键词static

static关键字有三种使用方式,可以修饰局部变量、全局变量和函数。

1修饰局部变量

首先,让我们看一下修饰局部变量的情况。

请先看这段代码,并思考输出结果。

void test()
{
       int a = 0;
       a++;
       printf("%d\n", a);

}

int main()
{
       int i = 0;
       for (i = 0; i < 10; i++) 
    {
              test();
    }
       return 0;
}

不难得出,运行结果为十个1。因为a是一个局部变量,当a离开函数以后,就被销毁了,然后再一次进入的时候a又重新创建了,所以a一直都是1

  

请再思考以下代的输出结果。

#include<stdio.h>
void test()
{
       static int a = 0;
       a++;
       printf("%d\n", a);
}


int main()
{
       int i = 0;

       for (i = 0; i < 10; i++) 
       {
              test();
       }

       return 0;
}

这段代码结果是什么呢?还是十个1吗?

我们运行一下

运行结果为1~10,那么为什么是这个结果呢,这段代码和上段代码的不同点就是static。那么,我们来总结一下static的第一个用法。

在不使用static修饰的情况下,局部变量的生命周期仅限于其所在函数的执行期间。每次函数调用时,都会重新创建并初始化这个局部变量。然而,当我们使用static修饰局部变量时,它的生命周期得到了延长。被static修饰的局部变量在函数调用结束后不会被销毁,而是保留其值,并在下一次函数调用时继续使用。这在循环中特别有用,因为可以在多次循环迭代中保持变量的值。

那么,static到底在计算机中做了什么事情,使得他不会被销毁了呢?在这里我们得拓展一个知识。

我们先来详细介绍内存的各个区域。一般将内存划分为三个主要区域:栈区、堆区和静态区。

  

栈区用于存储局部变量、函数参数等临时的变量。栈区的内存由编译器自动管理,它在函数调用时分配内存,在函数返回时释放内存。所以,栈区的数据在进入作用域时创建,在离开作用域时销毁。

堆区用于存储动态分配的内存,例如使用malloccallocreallocfree函数进行内存分配和释放。关于堆区和动态内存分配的更多内容将在后续文章中进行详细介绍。

静态区用于存储静态变量和全局变量。与栈区不同,静态区的数据在程序开始执行时创建,并直到程序结束后才释放。静态变量具有持久性,其值在函数调用之间保持不变。

在上文的代码片段中,我们使用了static关键字来修饰变量a,这将使a被存储在静态区。这意味着变量a在创建后会一直存在,直到程序结束。当我们通过循环进行第二次、第三次甚至第n次迭代时, a只会被创建一次。需要注意的是,尽管static修饰的局部变量的生命周期被延长,但其作用域仍然只限于声明它的块内。

综上所述,栈区和静态区在变量的生命周期和作用域上有所不同。栈区中的数据在进入和离开作用域时创建和销毁,而静态区中的数据在程序执行期间始终存在,并具有持久性。此外,虽然static修饰的局部变量延长了其生命周期,但其作用域仍然限于声明它的块内,与全局变量不同,全局变量的作用域覆盖整个程序。

2.修饰全局变量

我们先通过阅读下面这两段代码来回顾一下之前全局变量的使用方法:

// 示例代码1:全局变量的正常使用

//示例代码1:全局变量的正常使用
int a = 5;
#include<stdio.h>
int main()
{
    printf("%d", a);
    return 0;
}
// 示例代码2:全局变量在两个源文件间的使用
//Test.c
int main()
{
    printf("%d", a); // 编译时可能会出现链接错误,因为a在当前文件中不可见
    return 0;
}

// Test2.c
static int a = 5; // 使用static修饰全局变量a,使其具有内部链接属性,只能在Test2.c文件内部使用

上述代码中,示例代码1展示了全局变量的正常使用方式,在一个.c文件内定义并在其他地方使用。示例代码2展示了全局变量在两个源文件之间的使用情况,需要使用extern关键字声明并引用。

如果我们给第二种形式的全局变量加上static关键字,会发生什么呢?让我们尝试编译以下代码。

当我们尝试编译时,会遇到错误。这表明使用static修饰的全局变量无法在其他文件中使用,相当于将其隔离到自己的文件中,使其他文件无法访问。

让我们现在解释一下static修饰全局变量的作用:

全局变量本身具有外部链接属性,这意味着在一个文件中定义的变量可以在其他文件中通过链接使用。但是,如果将全局变量使用static修饰,它的外部链接属性就会变为内部链接属性,该全局变量只能在所在的源文件内部使用。

使用static修饰符,将外部链接属性更改为内部链接属性,从而使全局变量的作用域变小。需要补充的是,任何变量都具有内部链接属性,当具有外部链接属性时,我们称之为外部链接属性。使用static修饰后,外部链接属性被剥离,只剩下内部链接属性。

此外,值得补充的是,在一个工程中,所有的.c文件经过编译和链接后将形成一个.exe可执行程序。

3.static修饰函数

将一个函数声明为静态的,与修饰全局变量一样,具有类似的效果。让我们看下面这段代码:

//Test.c
#include <stdio.h>
extern int Add(int x, int y); // 在其他源文件中定义的Add函数
int main()
{
    int a = 1;
    int b = 2;
    int c = Add(a, b);
    printf("c = %d", c);
    return 0;

}

//Test2.c
static int Add(int x, int y) // 使用static修饰的Add函数,只能在当前源文件内部使用
{
    return x + y;
}

以上代码中,我们声明了一个函数Add,并在Test.c文件中调用它。该Add函数在另一个源文件Test2.c中被定义。然而,如果我们将Add函数声明为静态的,它就无法在Test.c文件中被识别和调用了。编译后会出现“无法解析的外部符号”的报错信息。这意味着静态修饰的函数只能在所在的源文件内部使用,而其他源文件无法使用它。

  

因此,总结一下静态修饰函数的作用:

函数本身具有外部链接属性,可以在其他源文件中引用和调用。

使用static修饰后,函数的外部链接属性变为内部链接属性。

静态修饰使得该函数只能在自己所在的源文件内部使用,而其他源文件无法使用它。

十二、#define定义常量和宏

(一)#define定义常量

在前面关于变量和常量的章节中已经提到了 #define 定义常量的概念,通过以下代码来简单复习一下:

//#define定义常量和宏
#include <stdio.h>
#define M 100
int main()
{
    printf("%d", M);
    return 0;
}

以上代码中,我们使用 #define 来定义常量 M,并将其设置为 100。在代码执行过程中,所有出现的 M 都会被替换为 100。

(二)宏

宏与定义常量有一些相似之处,但也有一些不同之处。我们先看一个使用宏的例子:

#include <stdio.h>
#define MAX(x, y) (x > y ? x : y)
int main()
{
    int a = 10;
    int b = 20;
    int m = MAX(a, b);
    printf("%d\n", m);
    return 0;

}

以上代码中,我们使用 #define 定义了一个宏 MAX,该宏接受两个参数 x 和 y。在代码执行过程中,MAX(a, b) 会被替换为 (x > y ? x : y)。具体而言,宏的替换是通过将参数以文本形式插入到宏定义中实现的。这种替换方式允许传递参数并生成相应的表达式。

综上所述,以上两个例子分别展示了 #define 定义常量和宏的用法。需要注意的是,在使用宏时要注意参数的正确性和宏替换的结果。

总结

本节主要讲了常见的关键词,以及#define定义常量与宏,如果本文对你的学习有所帮助,请不要忘记留下您免费的赞和关注哦!!

本章未完,欲知后事如何,请看下节!


时光荏苒,我的博客再次焕发活力,将继续为大家带来关于C语言入门的精彩内容。

我相信,通过我的博客,读者们能够逐步提升自己的编程能力,从小白成长为初级程序员,掌握C语言编程的精髓。C语言是一个开启编程世界大门的重要里程碑,它不仅有助于培养逻辑思维能力和解决问题的能力,也为进一步学习其他编程语言打下了坚实的基础。

无论是从事软件开发、嵌入式系统还是科学计算,C语言都是不可或缺的工具之一。通过我的博客,我希望能够激发读者们对编程的热情,并为他们的职业发展打下坚实的基础。

让我们一同踏上C语言的探索之旅,通过博客中的内容和交流互动,共同成长、共同进步。期待与你们一起分享编程的乐趣和成就,让我们一同开启C语言编程的奇妙之旅!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值