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

  

 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;
}

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3DMAX森林树木植物插件ForestPackLite教程

3DMAX森林树木植物插件ForestPackLite教程 Forest Pack是世界上最受欢迎的散布插件。它提供了一个完整的解决方案来创建大面积的物体&#xff0c;从树木和植物到建筑、人群、骨料、地面覆盖物、岩石等等。如果你能为它建模&#xff0c;森林包就能把它分散开来。 无数工作室依靠…

安装Nginx时报:./configure: error: can not define uint32_t

安装版本&#xff1a;v.1.25.3 安装命令&#xff1a; ./configure --prefix/opt/nginx/1.25.3 && make && make install 执行命令后出现异常&#xff0c;如图&#xff1a; 解决方法&#xff1a; yum install -y kernel-headers kernel-devel gcc make

算数通关村第十一关-白银挑战位运算高频题

位移的运算 位1的个数 描述 : 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位数为 1 的个数&#xff08;也被称为汉明重量&#xff09;。 题目 : LeetCode 191.位1的个数 191. 位1的个数…

Java入门篇 之 抽象类接口

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

配置VNC环境时,出现xauth: file /root/.Xauthority does not exist的解决方案。

问题描述 在配置VNC&#xff08;Virtual Network Computing&#xff09;环境的过程时&#xff0c;首先安装了tigervnc-server包。在使用&#xff1a; vncserver命令创建VNC会话号的时候出现了一个报错&#xff1a;xauth: file /root/.Xauthority does not exist 原因分析&…

大数据HCIE成神之路之数学(3)——概率论

概率论 1.1 概率论内容介绍1.1.1 概率论介绍1.1.2 实验介绍 1.2 概率论内容实现1.2.1 均值实现1.2.2 方差实现1.2.3 标准差实现1.2.4 协方差实现1.2.5 相关系数1.2.6 二项分布实现1.2.7 泊松分布实现1.2.8 正态分布1.2.9 指数分布1.2.10 中心极限定理的验证 1.1 概率论内容介绍…

Sql Server 2017主从配置之:发布订阅

使用发布订阅模式搭建Sql Server 2017主从同步&#xff0c;类似事件通知机制&#xff0c;基本可以做到准实时同步&#xff0c;可以同时做到一对多的数据同步。 不过发布订阅模式&#xff0c;只能同时数据&#xff0c;不能同步表结构。在创建发布的时候&#xff0c;需要选择需要…

Hive调优

1.参数配置优化 设定Hive参数有三种方式&#xff1a; &#xff08;1&#xff09;配置Hive文件 当修改配置Hive文件的设定后&#xff0c;对本机启动的所有Hive进程都有效&#xff0c;因此配置是全局性的。 一般地&#xff0c;Hive的配置文件包括两部分&#xff1a; a&#xff…

使用Spring Boot结合JustAuth实现支付宝、微信、微博扫码登录功能

使用Spring Boot结合JustAuth实现支付宝、微信、微博扫码登录功能 在使用Spring Boot结合JustAuth实现支付宝、微信、微博扫码登录功能之前&#xff0c;需要先确保已经配置好Spring Boot项目&#xff0c;并且添加了JustAuth的依赖。你可以在项目的pom.xml文件中添加如下依赖&a…

spass-二元变量相关分析

基础概念 计算相关系数r&#xff1a;利用样本数据计算样本相关系数&#xff0c;样本相关系数反映了两变量间线性相关程度的强弱。相关系数的取值范围界于-1与1之间&#xff0c;即-1≤r≤1 当0<r ≤ 1&#xff0c;表明变量之间存在正相关关系&#xff1b; 当-1 ≤ r…

BatchNormalization:解决神经网络中的内部协变量偏移问题

ICML2015 截至目前51172引 论文链接 代码连接(planing) 文章提出的问题 减少神经网络隐藏层中的”内部协变量偏移”问题。 在机器学习领域存在“协变量偏移”问题,问题的前提是我们划分数据集的时候,训练集和测试集往往假设是独立同分布(i.i.d)的,这种独立同分布更有利于…

C++--哈希表--散列--冲突--哈希闭散列模拟实现

文章目录 哈希概念一、哈希表闭散列的模拟实现二、开散列(哈希桶)的模拟实现数据类型定义析构函数插入查找删除 哈希概念 unordered系列的关联式容器之所以效率比较高&#xff0c;是因为其底层使用了哈希结构。 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没…

校园服装定制服务预约小程序的效果如何

对校园服装定制商家而言&#xff0c;如今线下流量稀缺&#xff0c;同行多且竞争激烈&#xff0c;同时这一行面对的消费者非大众&#xff0c;因此各品牌间都在通过各种方式进行同城或多地的客户拓展&#xff0c;但线下方式无疑是比较低效的。线上是一个不错的选择&#xff0c;不…

元素水平垂直居中

方法一&#xff1a;定位transform 方法二&#xff1a;flex布局 方法三&#xff1a;定位margin【需要child 元素自身的宽高】 相关HTML代码&#xff1a; <div class"parent"><div class"child"></div> </div> 方法一&#xff1a…

pythongui实时闹钟

# codinggbk import tkinter as tk from time import strftime# 创建一个主窗口 root tk.Tk() root.title("实时闹钟")# 设置窗口的大小不可变 root.resizable(False, False)# 设置窗口始终保持在最上层 root.attributes(-topmost, True)# 更新时间的函数 def time(…

力扣 字母异位词分组 哈表 集合

&#x1f468;‍&#x1f3eb; 力扣 字母异位词分组 ⭐ 思路 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符串分别进行排序之后得到的字符串一定是相同的&#xff0c;故可以将排序之后的字符串作为哈希表的键。 &#x1f351; AC code class Solut…

Docker中快速安装RabbitMQ

文章目录 前言一、安装Docker二、安装RabbitMQ无脑命令行运行 总结 前言 在Ubuntu中的Docker容器中快速安装RabbitMQ&#xff0c;亲测有效&#xff0c;不废话&#xff0c;上操作。 一、安装Docker 直接按照Docker官方教程操作&#xff1a;官方安装教程 点进官网&#xff0c;往…

Springboot 对于数据库字段加密方案(此方案是对字符串处理的方案)

背景:在erp开发中&#xff0c;有些用户比较敏感数据库里的数据比较敏感&#xff0c;系统给用户部署后&#xff0c;公司也不想让任何人看到数据&#xff0c;所以就有了数据库字段加密方案。 技术 spring boot mybatisplus 3.3.1 mybatisplus 实际提供了 字段加密方案 第一 他…

pr出现由于找不到msvcp110.dll,无法继续执行代码怎么办?如何修复

为什么我们在打开运行电脑软件会出现msvcr110.dll无法继续执行此代码的问题呢&#xff1f;因为msvcr110.dll是Microsoft Visual C Redistributable Package for Visual Studio 2013的一个动态链接库。它是一个重要的组件&#xff0c;用于帮助游戏和软件运行。如果某个程序是用它…

JDK1.5 新特性【泛型】

前言 泛型在 JavaSE 阶段是学习过的&#xff0c;但是毕竟处理定义一些简单的集合就很少用到它了&#xff0c;至于最近 Flink 中遇到的 泛型方法&#xff0c;更是感觉闻所未闻&#xff0c;以及源码中加在接口、方法、类前的各种 <T,V> 让我实在自觉羞愧&#xff0c;于是今…