C语言基础篇4:变量、存储、库函数

news2024/11/16 15:59:44

  

 1 局部变量和全局变量

        在介绍局部变量和全局变量前,先了解一些关于作用域方面的内容。作用域的作用就是决定程序中的哪些语句是可用的,换句话说,就是程序中的可见性。作用域有局部作用域和全局作用域,那么局部变量就具有局部作用域,而全局变量就具有全局作用域。

1.1 局部变量

        在一个函数的内部定义的变量就是局部变量,无法被别的函数使用。函数的形参也属于局部变量,作用范围仅限于函数内部的语句块。

【示例1.1】局部变量的作用域

#include <stdio.h>
int main(){
    int i = 1;
    if(i > 0){
        int j = 2;
        if(j > 0){
            int m = 3;
            printf("all number %d %d %d \n",i,j,m);
        }
    }
    return 0;
}

        在C语言中位于不同作用域的变量可以使用相同的标识符,也就是在这种情况下,变量名可以相同。如果在一个函数中,内层作用域中定义的变量和已经声明过的某个外层变量有相同的名字,那么内层作用域中的变量将覆盖外层作用域中的那个变量。

1.2 全局变量

        程序的编译单位是源文件,上面说到,在函数中定义的变量称为局部变量。如果一个变量在所有的函数的外部声明,这个变量就是全局变量。全局变量是可以在程序中的任何位置进行访问的变量。

【注意】全局变量不属于某个函数,而是整个源文件。但如果外部文件要进行调用,需要使用extern进行引用修饰。

        定义全局变量的作用是增加了函数间数据联系的渠道。由于同一个文件中的所有函数都能引用全局变量的值,因此如果在一个函数中改变了全局变量的值,就会影响到其他函数。

【示例1.2】使用全局变量

#include <stdio.h>
int global = 100; //定义全局变量
void Store1Price();
void Store2Price();
void Store3Price();
void ChangePrice();
int main(){
    printf("调整之前,全局变量的值是: %d \n",global);
    Store1Price();
    Store2Price();
    Store3Price();
    ChangePrice();//修改全局变量的值
    printf("调整之后,全局变量的值是: %d \n",global);
    Store1Price();
    Store2Price();
    Store3Price();
}
void Store1Price(){
    printf("全局变量的值是:%d \n",global);
}
void Store2Price(){
    printf("全局变量的值是:%d \n",global);
}
void Store3Price(){
    printf("全局变量的值是:%d \n",global);
}
void ChangePrice(){
    printf("是否需要改变全局变量的值,希望改成:");
    scanf("%d",&global);
}

2 变量的存储类别

        变量的存储类别决定变量什么时候被分配到指定的内存空间中,以及在什么时候释放内存空间。因此,存储类别就是为变量分配使用内存空间的方式,也可以称为存储方式。变量的存储类别分为两种形式,动态存储和静态存储。并且可以通过存储类修改符来告诉编译器要处理什么样的类型变量。具体有自动(auto)、静态(static)、寄存器(register)和外部(extern)4种。

2.1 静态存储和动态存储

         从变量的产生时间上可以分为静态存储和动态存储。

         静态存储就是指在程序运行时分配的固定的存储方式,而动态存储则是在程序运行期间根据需要进行动态的分配存储空间。

        要理解动态存储和静态存储方式,首先要了解内存中用户存储空间的基本情况。系统提供用户的存储空间可以分为3个部分:程序区、静态存储区和动态存储区。

        其中,程序区用来存放用户要执行的程序段。数据分别放在静态存储区和动态存储区中。

        静态存储的变量位于内存的静态存储区,全局变量都保存在静态存储区中,因此全局变量从程序执行时开发分配存储单元,直到程序运行结束,才释放其所占的存储单元。

        在动态存储区中存储跟堆栈操作相关的数据有关,堆栈中的数据随着进栈出栈操作而变化,当变量被弹出堆栈以后,其生存周期也就结束了。在调用函数时,其局部变量也被保存到动态存储区中,当函数结束执行,返回到主调函数时,变量所占用的空间将被释放,此时局部变量也将消失。由此可见,如果一个函数被调用了两次,其中变量的存储空间可能为不同的地址。

        个存储区所存放的数据内容如下:

        1、静态存储区:存储全局变量,在程序执行过程中,全局变量占据固定的内存空间,直到程序执行完毕才释放内存。

        2、动态存储区:

                1)自动变量,在函数调用时分配存储空间,调用完成释放存储空间。

                2)函数调用时现场保护和返回地址,在函数被调用时分配内存空间。

                3)函数形参:只有在调用该函数时才能为形参分配内存空间,调用完以后会将所有的空间释放掉。

        从上述分析可知,静态存储变量是一直都存在的,而动态存储变量则是根据函数执行过程决定是否存在还是消失。

2.2 auto变量

        该存储类型是C语言中使用最广泛的一种类型。C语音规定,函数内凡未加存储类型说明的变量,默认都是自动变量,也就是说自动变量可以省去说明符auto。

        自动变量有以下特点:

        1、自动变量的作用域仅限于定义该变量的个体内。在函数中定义的自动变量,只在该函数中有效。在复合语句中定义的自动变量只在该复合语句中有效。

        2、自动变量属于动态存储方式,只有在使用它时,即定义该变量的函数被调用时才给它分配存储单元,函数调用结束,释放存储单元。因此函数调用结束后,自动变量的值不能保留。同样在复合语句中定义的自动变量,在退出复合语句后也不能在使用。
 

2.3 static变量

        在编写程序的过程中,有些函数的局部变量的值在函数调用结束后不希望值消失,也就是不释放该变量所占用的存储单元;同样,有时在程序设计中也希望某些外部变量只限于被本文件引用,而不能被其他文件引用。这时就需要使用关键词static对变量进行声明。

        1、静态局部变量

        在局部变量的说明前加上static说明符就构成了静态局部变量。

        静态局部变量属于静态存储方式,具有以下特点:

        1)、静态局部变量在函数内定义,但与自动变量不同,当调用时就已经存在,退出函数时消失。静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序整个运行期间都不会释放,静态局部便令始终存储,也就是说它的生存期为整个源程序。

        2)、静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出函数后,尽管改变量还存在,但不能使用它,如果再次调用其定义的函数,又可以继续使用。

        3)、对基本类型的静态局部变量,如果在声明时没有赋初始值,则系统自动赋值0。而对于自动变量不赋初值,其值是不确定的。

【示例2.3】使用静态变量

#include <stdio.h>
int add(int x){
    static int n = 0;
    n = n + x;
    return n;
}
int main(){
    int i,j,sum;
    printf("请输入一个整数:\n");
    scanf("%d",&i);
    for (j = 1;  j< i; j++) {
        sum = add(j);
        printf("%d:%d \n",j,sum);
    }
    return 0;

}

        上面代码中的静态局部变量n是一种生存期为真个源程序的变量。每次调用add函数时,静态局部变量n都保存了前次被调用后留下的值。如果将static改成auto,那么运行结果是:

 

        因此,从运行结果可以看出,自动变量占动态存储区空间,而不占静态存储区空间,导致每次调用后变量n的值都被释放,每次调用add方法时,n的值都是从0开始。

        2 静态全局变量

        在全局变量的变量类型说明之前加上static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量自然也是静态存储方式。两者在存储方式上并不同。两者的区别在于作用域不同,非静态全局变量的作用域是整个源程序,当一个源程序有多个源文件组成时,非静态的全局变量在各个源文件都是有效的。

        例如,在file1.c中定义了非静态全局变量i,则在其他的源文件(如file2.c)中也可以调用;而静态全局变量则限制了其作用域,即只在定义该变量的源文件中有效,在同一源程序的其他源文件中不能使用它。例如,在file1.c中定义了静态全局变量,则在其他的源文件(file2.c)中不可以调用。

        【说明】static说明符在不同的地方所起的作用是不同的。将局部变量改变为静态变量后是改变了它的存储方式,即改变了其生存周期。将全局变量改变为静态变量后是改变了它的作用域,限制其使用范围。

2.4 register变量

        通常变量的值是存放在内存中,当对一个变量频繁读写时,则需要反复访问内存,从而花费大量的时间。为了提高效率,C语言提供了另一种变量,即寄存器变量。这种变量允许将局部变量的值存放在CPU的寄存器中,使用时不需要访问内存,而直接从寄存器中读写。寄存器变量的说明符是register。

        对寄存器变量还需要说明以下几点:

        用户无法获取寄存器变量的地址,因为绝大多数计算机的硬件寄存器都不占用内存地址。而且,即使编译器忽略register而把变量存放在可设定的内存中,也是无法获取变量的地址的。

        如果想要有效地利用寄存器register关键字,必须像汇编语言程序员那样了解处理器的内部结构,直到可用于存储变量的寄存器的数量、种类以及工作方式。但是,对于这些细节不同的计算机还可能是不同的。因此,对于一个要具备可移植的程序来说,regis作用不大。

2.5 extern变量

        由于C语言允许将一个较大的程序分成若干独立模块文件分别编译,如果一个源文件中的函数想引用其他源文件中的变量,就可以用extern来声明外部变量,也就是说extern变量可以扩展外部变量的作用域。

        1、在多文件的程序中声明外部变量

        定义时默认static关键字的外部变量,即为非静态外部变量。其他源文件中的函数,引用非静态外部变量时,需要在引用函数所在的源文件进行如下声明:

extern 数据类型 外部变量表;

        注意:在函数内的extern变量说明,表示引用本源文件中的外部变量,而函数外的extern变量说明,表示引用其他文件中的外部变量。

例如,有一个源程序由源文件file1.c和file2.c组成。在file1.c和file2.c两个文件中都要使用x y z 三个变量。在file1.c文件中把x y z 都定音为外部变量。在file2.c文件中用extern把三个变量声明为外部变量,表示这些变量已在其他文件中定义,编译系统不在为它们分配内容空间。对构造类型的外部变量(如数组等)可以在声明时作为初始化赋值,如果不赋初值,则系统自动定义它们的初始值为0。

        2、在一个文件内声明外部变量

        如果外部变量不在文件的开头定义,其有效的作用范围只限于定义到文件结束处。此时如果想在定义该变量的位置之前调用此变量,则应该在应用之前用关键字extern对该变量作“外部变量声明”。

3 内部函数和外部函数

        函数时C语言最小单位,往往把一个函数或多个函数保存为一个文件,这个文件称为源文件。定义一个函数,这个函数就要被另外的函数所调用。但当一个源程序由多个源文件组成时,可以指定函数不能被其他文件调用,这样c语言又把函数分为两类:内部函数和外部函数。

3.1 内部函数

        定义的函数只被所在的源文件中使用,称为内部函数。内部函数又称为静态函数。使用内部函数,可以是函数只局限于函数所在的源文件中,如果在不同的源文件中有同名的内部函数,这些同名的内部函数也不互相干扰。

        在定义内部函数时,要在函数返回值和函数名前加上关键字static进行修饰。

        static 返回值类型 函数名(参数列表)

        使用内部函数的好处,不能同的开发者可以分别编写不同的函数,而不必担心函数是否会和其他的源文件的函数重名。

【示例 3.1】使用内部函数,通过一个函数对字符串进行赋值,在通过一个函数对字符串进行输出显示。

#include <stdio.h>
static char* GetString(char* pString){
    return pString;
}
static void ShowString(char* pString){
    printf("%s\n",pString);
}
int main(){
    char* pString;
    pString = GetString("hello!");
    ShowString(pString);
    return 0;
}

3.2 外部函数

        与内部函数相反的是外部函数,外部函数就是可以被其他源文件调用的函数。定义外部函数使用关键字extern进行修饰。在使用一个外部函数时,要先用关键字extern声明所用的函数时外部函数。例如,函数头可以写成:extern int add(int i,int j);这样add函数就可以被其他文件调用了。

        注意:C语言定义函数时,如果不指明函数是内部函数或外部函数,那么默认将函数指定为外部函数。也就是说,定义外部函数时,可以省略extern关键字。

4 数学函数

        在程序中经常会使用一些数学的运算或者公式,这时就要用到数学函数。数学函数的返回值都是双精度数据类型的,用到它们的程序中都包含头文件math.h

4.1 绝对值函数

        abs 函数的功能是求整数的绝对值,参数x是所要求的绝对值的整数。定义形式如下:

        int abs(int x)   

#include <stdio.h>
#include <math.h>
int absTest();
int main(){

    int result = absTest(-10);
    printf("绝对值是:%d",result);
    return 0;

}
int absTest(int x){
    int result = abs(x);
    return result;
}

        labs函数:求长整数的绝对值。定义形式如下:long labs(long x)

#include <stdio.h>
#include <math.h>
int absTest();
long labsTest();
int main(){
    long result = labsTest(-1234567890L);
    printf("绝对值是:%d",result);
    return 0;

}
long labsTest(long x){
    int result = labs(x);
    return result;
}

        fabs函数:返回浮点数的绝对值。定义形式如下:

        double fabs(double n)

        

#include <stdio.h>
#include <math.h>
int absTest();
long labsTest();
double fabsTest();
int main(){
    double result = fabsTest(-123.45);
    printf("绝对值是:%lf",result);
    return 0;

}
double fabsTest(double x){
    double result = fabs(x);
    return result;
}

5 字符和字符串函数(例子在后面)

        使用字符串函数时要包含头文件string.h,而使用字符函数要包含头文件ctype.h

5.1 isalpha函数 

        用来检测字母,如果参数(ch)是字母表中的字母(大写或小写),则返回非0。要包含头文件ctype.h。定义形式:int isalpah(int ch)。

5.2 isdigit函数

        用来检测数字,如果ch是数字则函数返回非0,否则返回0。要包含头文件ctype.h。定义形式:int isdigit(int ch)。

5.3 isalnum函数

        用来检测字母或数字,如果参数时字母表中的一个字母或数字,则函数返回非0。否则返回0。要包含头文件ctype.h。定义形式:int isalnum(int ch)。

【示例2.1】使用字符函数判断输入字符。

#include <stdio.h>
#include <ctype.h>
void SwitchShow(char c);
int main(){
    //定义字符变量,用来接收输入的字符
    char cCharPut;
    //定义字符变量,用来接收回车
    char cCharTemp;
    //提示消息
    printf("第一次输入字符");
    //输入字符
    scanf("%c",&cCharPut);
    //调用函数进行判断
    SwitchShow(cCharPut);
    //接受回车
    cCharTemp = getchar();
    //消息提示
    printf("进行第二次输入字符:");
    //输入字符
    scanf("%c",&cCharPut);
    //调用函数进行判断
    SwitchShow(cCharPut);
    //接受回车
    cCharTemp = getchar();
    //消息提示
    printf("进行第三次输入字符:");
    //输入字符
    scanf("%c",&cCharPut);
    //调用函数进行判断
    SwitchShow(cCharPut);
    //程序结束
    return 0;
}
void SwitchShow(char cChar){
    //判断是否是字母
    if(isalpha(cChar)){
        printf("您输入的是字符表里的字母:%c \n",cChar);
    }
    //判断是否是数字
    if(isdigit(cChar)){
        printf("您输入的是阿拉伯数字:%c \n",cChar);
    }
    //判断是否是字母或数字
    if(isalnum(cChar)){
        printf("你输入的是包含字母和数字:%c \n",cChar);
    }
    else{
        printf("您输入的既不是字母也不是数字:%c \n",cChar);
    }
}

5.4 strchr函数

        返回由str所指向的字符串中首先出现ch的位置指针,如果未发现与ch匹配的字符,则返回空指针。需要以如头文件 string.h。定义如下:

char strchar(char *str,char ch)

【示例】使用strchr函数查找字符串s中指定字符u的首位置。

#include <stdio.h>
#include <string.h>
int main(){
    //定义字符数组
    char s[20];
    //声明要查找的字符
    char *p,c = 'u';
    //复制字符串
    strcpy(s,"good luck to you");
    //查找字符
    p = strchr(s,c);
    //输出字符首位置
    if(p){
        printf("字符%c在数组的位置是:%d\n",c,p-s);
    }else{
        printf("字符u在数组中没找到\n");
    }
    return 0;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1227071.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】:模板的使用

目录 1、泛型编程 2、函数模板 2.1、函数模板概念 2.2、函数模板格式 2.3、函数模板的原理 2.4、函数模板的实例化 2.6、模板参数的匹配原则 3、类模板 3.1、 类模板的定义格式 3.2、 类模板的实例化 4、非类型模板参数 5、模板的特化 5.1、函数模板特化 5.2、类模…

2.如何使用Python官方文档

文章目录 1.文档什么时候用2.Python 3.11有什么新的功能3.Python 3.11教程4.Python 标准库概述内置函数内置类型内置异常文本处理服务 1.文档什么时候用 一般是在接触到一门新的语言的时候&#xff0c;是要详细阅读的&#xff0c;因为很多在开发的时候踩的这些坑在文档里已经提…

基于Prometheus快速搭建网络质量监控平台

基于Prometheus快速搭建网络质量监控平台 前言 针对一些临时搭建的网络场景&#xff08;例如&#xff1a;各种临时发布会&#xff0c;演唱会等&#xff09;&#xff0c;为了检验网络质量的以及确保管理员在网络出现异常情况时可以及时发现&#xff0c;需要部署一套监控软件用于…

a标签下载文件与解决浏览器默认打开某些格式文件的问题

前言 在实际项目中&#xff0c;我们通常会遇到这么一个需求&#xff1a;后端给前端返回一个任意文件类型的完整的url路径&#xff0c;前端拿到这个路径直接通过浏览器下载文件到本地。我想大家应该都会首先想到使用HTML中的<a>标签&#xff0c;&#xff0c;因为<a>…

国学---佛系算吉凶~

佛系算吉凶咯~&#xff0c;正经走访深山庙宇&#xff0c;前辈老人&#xff0c;经过调研后&#xff0c;搭建的轻衍计算模型&#xff0c;团队对国学的初次信息化尝试。 共享给有需要的朋友&#xff0c;准不准没关系&#xff0c;开心最重要。 后续还有财富&#xff0c;事业&…

【Python】解析CPP类定义代码,获取UML类图信息

参考 & 鸣谢 CppHeaderParser - 官方文档Python解析C头文件win10直接获得文件绝对路径的方法总结 目的 解析CPP头文件中的类定义&#xff0c;获取UML中的属性。用于画UML类图。如下所示格式&#xff0c;图片来源-链接 即获取&#xff0c;类名&#xff0c;成员函数&#x…

05_SHELL编程之文本处理工具SED

typora-root-url: pictures课程目标 掌握sed的基本语法结构 熟悉sed常用的命令&#xff0c;如打印p&#xff0c;删除d&#xff0c;插入i等 Windows&#xff1a;​ Linux&#xff1a; vim vi gedit nano emacs 一、sed介绍 1. sed的工作流程 首先sed把当前正在处理的行保存…

python urllib open 头部信息错误

header 有些字符在 lighttpd server 中无法正常解析,需要转换 quteo 可以转换 就跨平台而言,Rust 和 python 一样优秀,看了在stm32 上使用 Rust 进行编程,从一定程度上,而言&#xff0c;稳定和安全性要比C 开发的好的多,说出来可能不信&#xff0c;在单片机上是可以对空指针进行…

力扣周赛372 模拟 思维 位运算 java

100131. 使三个字符串相等 ⭐ AC code class Solution {public int findMinimumOperations(String s1, String s2, String s3) {int len1 s1.length();int len2 s2.length();int len3 s3.length();int n Math.min(len1,len2);n Math.min(n,len3);int i 0;while(i < n…

代码随想录二刷 | 数组 | 移除元素

代码随想录二刷 &#xff5c; 数组 &#xff5c; 移除元素 题目描述解题思路 & 代码实现暴力解法双指针法 题目描述 27. 移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用…

Ubuntu(Linux)的基本操作

基本操作三步走 1、输入vim code.c点击i&#xff08;出现insert&#xff09;表示可以编辑代码编辑代码之后按下esc&#xff08;退出编辑模式&#xff09;按下shift:&#xff08;冒号&#xff09;wq&#xff08;退出文件&#xff09;2、输入gcc code.c&#xff08;进行编译代码…

RobotFramework框架之导入自己打包的python程序(十五)

引言 RobotFramework自动化框架&#xff08;以下简称RF&#xff09;之前文章我们讲了通过import第三方的library&#xff08;RequestsLibrary等&#xff09;&#xff0c;在实际项目中第三方的包并不能满足我们的需要&#xff0c;此时我们可自己编写python模块&#xff08;.py文…

命令执行相关函数及各类命令执行绕过技巧

相关函数 &#xff08;命令注入&#xff09; 命令执行的绕过

MySQL 的执行原理(五)

5.6 再深入查询优化 5.6.1. 全局考虑性能优化 5.6.3.1. 为什么查询速度会慢 在尝试编写快速的查询之前&#xff0c;需要清楚一点&#xff0c;真正重要是响应时间。如果把查询看作是一个任务&#xff0c;那么它由一系列子任务组成&#xff0c;每个子任务都会消耗一定的时间。…

YOLOv8优化策略:轻量级Backbone改进 | VanillaNet极简神经网络模型 | 华为诺亚2023

🚀🚀🚀本文改进:一种极简的神经网络模型 VanillaNet,支持vanillanet_5, vanillanet_6, vanillanet_7, vanillanet_8, vanillanet_9, vanillanet_10, vanillanet_11等版本 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到创新,…

大模型的语言能力

NLP作为一个领域为基础模型开辟了道路。虽然这些模型在标准基准测试中占据主导地位&#xff0c;但这些模型目前获得的能力与那些将语言描述为人类交流和思维的复杂系统的能力之间存在明显的差距。针对这一点&#xff0c;我们强调语言变异的全部范围&#xff08;例如&#xff0c…

【设计模式】创建型设计模式

创建型设计模式 文章目录 创建型设计模式一、概述二、单例模式三、工厂模式3.1 简单工厂模式&#xff08;静态工厂模式&#xff09;3.2 工厂方法模式3.3 抽象工厂模式3.3 工厂模式小结 四、原型模式五、建造者模式 一、概述 这些设计模式提供了一种在创建对象的同时隐藏创建逻…

Java入门篇 之 抽象类接口

本篇碎碎念&#xff1a;个人认为压力是一种前进的动力&#xff0c;但是不要有太多压力&#xff0c;不然会使心情烦躁&#xff0c;会控制不住自己的情绪&#xff0c;会在一个临界值爆发&#xff0c;一旦爆发&#xff0c;将迟迟不能消散 今日份励志文案: 努力的背后必有加倍的赏赐…

用cmd看星球大战大电影,c++版本全集星球大战,超长多细节

用cmd看星球大战 最近发现了一个有趣的指令。 是不是感觉很insteresting呢 教程 进入控制面板&#xff0c;点击系统与安全 然后&#xff0c;进入以后&#xff0c;点击启用或关闭 Windows 功能 启用Telnet Client并点击确定 用快捷键winr打开我们的cmd 输入指令 telnet towe…

使用百度翻译API或腾讯翻译API做一个小翻译工具

前言 书到用时方恨少&#xff0c;只能临时抱佛脚。英文pdf看不懂&#xff0c;压根看不懂。正好有百度翻译API和腾讯翻译API&#xff0c;就利用两个API自己写一个简单的翻译工具&#xff0c;充分利用资源&#xff0c;用的也放心。 前期准备 关键肯定是两大厂的翻译API&#x…