C语言存储类别、链接和内存管理:基础概念,作用域和链接种类

本文深入探讨C语言的存储类别、链接性质和内存管理,包括基础概念如对象与标识符,作用域的四种类型:块作用域、函数作用域、函数原型作用域和文件作用域,以及链接的无链接和外部链接/内部链接。通过实例解析,阐述了这些概念如何影响代码的执行和变量的生命周期。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C语言存储类别、链接和内存管理

基础概念

首先就是介绍一些基本概念,然后就是分别扩展这些概念的属性:

  • 对象:内存中一个存储单位存储的具体的值
  • 标识符 / 左值:就是代码中代表内存中对象的值,比如:
int sign=1;

中的sign就是一个标识符,sign+1就不是一个标识符,因为它不代表内存中的任何一个值。

但是结合到指针就会再复杂一点:

char address[]="hello world";

这里*(address+1)也可以算是一个标识符,因为其也代表一个内存地址。

标识符有一个特性就是是否可修改。

C语言中的二维数组与指针说:

const char* unchangeAbleString="hello world";

char* unchangeAbleString="hello world";

的效果是一样的,这里在是否可修改的角度上来说明一下:

image-20210407222228931

这里的const是保证"hello world"的这块字符串是不可修改的,*unchangeableString还是可以指向其他地址的,比如下面的代码就是错误的:

#include "stdio.h"

int main(int argc,char* argv[]) {
    char* unchangeableString="hello world";
    unchangeableString[0]='q';
    printf("%s",unchangeableString);
}

因为这里我们尝试使用unchangeableString[0]去修改const设定的值,肯定是改不动的。

但是上面我们提到,让unchangeableString去指向新的地址,却是没有问题的,比如下面的代码:

#include "stdio.h"

int main(int argc,char* argv[]) {
    char* unchangeableString="hello world";
    char* newString="hello c";
    unchangeableString=newString;
    printf("%s",unchangeableString);
}

这样就介绍了基本概念,接下来就是这些基础概念与之对应的属性:

对象
存储期
标识符
作用域
链接

作用域

作用域共分为:

Category
块作用域
函数作用域
函数原型作用域
文件作用域 / 全局变量

块作用域

这个很简单,被套在{}之间的作用域,这个有个很有意思的对比,下面相同类型的代码,首先在PHP中:

<?php
function param(){
	while (true) {
		$data=1;
		break;
	}
  // 这里是可以访问上面{}中的内容的
	print $data.PHP_EOL;
}
param();
?>

中,在{}外部是可以访问在其中定义的内容的,但是在C语言中:

#include "stdio.h"

int main(int argc,char* argv[]) {
    while (1){
        short int data=1;
        break;
    }
    // 这里会报错,表明没有这个值
    printf("%d",data);
}

这里有一些特殊的情况,就是类似下面这种:

for (int i = 0; i < 10; ++i) {
        printf("%d\n",i);
    }

这种,int i是在{}外部定义的,也可以使用。

函数作用域

这个值很有意思,和goto有关,看下面的代码:

#include "stdio.h"

int main(int argc,char* argv[]) {
    getIdo:printf("You get ido number\n");
    // 这是个死循环
    int i=0;
    while (i<3){
        i++;
        if (i%2==0){
            goto getIdo;
        }
    }
}

goto之间的参数int i=0会一直有效,所以是个死循环。修改成下面的就可以了:

#include "stdio.h"

int main(int argc,char* argv[]) {
  	// 将这个值移动出来
    int i=0;
    getIdo:printf("You get ido number\n");
    while (i<3){
        i++;
        if (i%2==0){
            goto getIdo;
        }
    }
}

函数原型作用域

这个就很简单了,就是说函数的参数,仅仅在该函数内部有效,比如:

#include "stdio.h"

int functionPrototype(int n1,int m1,int a[n1][m1]);

int main(int argc,char* argv[]) {
    int n,m;
    n=1;
    m=1;
    int a[1][1]= {
            {1}
    };
    functionPrototype(n,m,a);
}
// 这里的 n,m,a 跟外部都没有关系
int functionPrototype(int n,int m,int a[n][m]){
    return 0;
}

文件作用域 / 全局变量

这个很简单,就是定义在函数外部的变量:

#include "stdio.h"

float PI=3.1415926;

void printPI();

int main(int argc,char* argv[]) {
    printf("PI is %f\n",PI);
    printPI();
}

void printPI(){
    printf("PI is %f\n",PI);
}

因为在任何地方都可以访问到这个值,所以也称为全局变量

链接

这个需要和上面的作用域关联起来看:

LinkCategory
外部链接
内部链接
无链接
块作用域
函数作用域
函数原型作用域
文件作用域

无链接

简单来说就是:

  • 块作用域
  • 函数作用域
  • 函数原型作用域

中的标识符都是没有链接的,仅在这些作用域内部使用。

外部链接 / 内部链接

这两个为什么要连在一起说呢?

在开始介绍前,先介绍一个名词:翻译单元,当前文件和其所包含的头文件组成。

这里举个例子:

比如这里我在同一个目录下首先定义一个文件:file1.c

#include <stdio.h>

void fun(void)
{
    printf("hello from fun.\n");
}

再定一个文件:file2.c

int main(void)
{
    fun();
    return 0;
}

注意!这里调用了一个在file1.c中定义的函数:fun()。然后调用gcc进行编译:

gcc file1.c file2.c

这样的方式就定义了一个翻译单元。


再来就是介绍内部链接:内部链接仅在一个翻译单元中使用,使用关键字:static标明。

这里扩充一下static的作用,可以更好的理解上面说的作用域。参考博客

这里先修改file1.c

#include <stdio.h>
// 注意这里的变量,会在 fil2.c 中也定义一个
static int staticInt=1;

void fun(void)
{
    printf("hello from fun.\n");
}

static void privateFunction(){
    printf("%d\n",staticInt);
}

再修改file2.c

#include "stdio.h"
// 这里的值在 file1.c 中也有,但是因为在 file2.c 中使用 static 定义为内部链接,所以不会跟这里起冲突
int staticInt=2;

int main(void)
{
    fun();
    printf("%d",staticInt);
    return 0;
}

同样,static void privateFunction()file2.c中也不能调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值