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

 

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

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

相关文章

Docker部署MinIO对象存储服务器结合Cpolar实现远程访问

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远…

YB506AB是一款理电池充、放电管理专用芯片,集成锂电池充电管理和降压DC-DC电路。

YB506AB 锂电转可充电AA/AAA电池专用SOC芯片 概述: YB506AB是一款理电池充、放电管理专用芯片&#xff0c;集成锂电池充电管理和降压DC-DC电路。充电过程满足锂电池三段式滑流/恒流/恒压充电规范&#xff0c;B506内部的线性充电电路采用了恒流可配置模式&#xff0c;可以通过…

【shell】 1、bash语法超详细介绍

文章目录 修改前缀路径dirname set常用函数参数变量local 返回值正则打印第 n 行获取行号核对数据库各表数量jq查询检查日志 sshpassexpect数组xargs bash manual 修改前缀 参考 export PS1"bash> "路径 dirname strip last component from file name dir$(…

Nodejs--Express框架使用

目录 一.概念 二.项目目录结构 三.app.js 四.项目需要的中间件 五.Mysql连接 六.日志配置 七.实体模型配置 八.统一结果封装 九.app.js的详细配置 十.自定义登录拦截器 十一.route路由配置 十二.controller处理 十二&#xff1a;静态页面&#xff1a; 十三&#xff…

Pytest自动化测试框架:mark用法---测试用例分组执行

pytest中的mark&#xff1a; mark主要用于在测试用例/测试类中给用例打标记(只能使用已注册的标记名)&#xff0c;实现测试分组功能&#xff0c;并能和其它插件配合设置测试方法执行顺序等。 如下图&#xff0c;现在需要只执行红色部分的测试方法&#xff0c;其它方法不执行&am…

辅助笔记-Jupyter Notebook的安装和使用

辅助笔记-Jupyter Notebook的安装和使用 文章目录 辅助笔记-Jupyter Notebook的安装和使用1. 安装Anaconda2. conda更换清华源3. Jupter Notebooks 使用技巧 笔记主要参考B站视频“最易上手的Python环境配置——Jupyter Notebook使用精讲”。 Jupyter Notebook (此前被称为IPyt…

学习教授LLM逻辑推理11.19

学习教授LLM逻辑推理 摘要1 引言2前言2.1事件关系提取2.2 演绎推理 3 揭示逻辑推理中的LLMS3.1 LLM如何执行任务3.1.1数据源3.1.2实验装置3.1.3 分析 3.2 LLM如何执行抽象多跳推理&#xff1f;3.2.1数据来源3.2.2 实验装置。3.2.3 分析。 4 逻辑推理教学4.1 LLM的上下文学习4.2…

国外客户发开发信怎么发?写外贸邮件方法?

如何给国外客户发开发信&#xff1f;给老外发外贸开发信的技巧&#xff1f; 与国外客户保持联系并积极开展业务合作变得至关重要。一种有效的方式是通过发展信件&#xff0c;这可以帮助建立关系、传递信息和促成商机。蜂邮将介绍如何向国外客户发开发信&#xff0c;以确保您的…

金融市场数据至上:QuestDB 为您的数据提供最优解 | 开源日报 No.81

vlang/v Stars: 34.7k License: MIT V 是一个开源项目&#xff0c;它是一种简单、易于学习的编程语言。该项目具有以下核心优势和主要功能&#xff1a; 简洁性&#xff1a;可以在周末内掌握这门语言。快速编译&#xff1a;使用 Clang 后端约为 110k loc/s&#xff0c;本地和…

MR素数测试及 pycryptodome库下 已知MR伪素数以及强伪证 生成指定伪随机数生成器绕过素性检测

MR素数测试在密码学库中应用广泛&#xff0c;通常作为BSPW的一部分来进行素数测试&#xff0c;由于在其算法中&#xff0c;有随机数的使用&#xff08;选择一个随机的base&#xff09;&#xff0c;若一个MR伪素数 n n n&#xff0c;已知其在某一个强伪证 a a a&#xff08;随机…

Leetcode—3.无重复字符的最长子串【中等】

2023每日刷题&#xff08;三十二&#xff09; Leetcode—3.无重复字符的最长子串 实现代码 class Solution { public:int lengthOfLongestSubstring(string s) {unordered_set<char> smap;int maxlen 0;int left 0;for(int i 0; i < s.size(); i) {while(smap.fi…

【精选】JSP技术知识点大合集

JSP简介 JSP介绍 JSP(全称Java Server Pages)Java服务端页面技术&#xff0c;是JavaEE平台下的技术规范。它允许使用特定的标签在HTML网页中插入Java代码&#xff0c;实现动态页面处理&#xff0c;所以JSP就是HTML与Java代码的复合体。JSP技术可以快速的实现一个页面的开发&am…

C++大神之路——环境篇

序 在我还在做后端的时候&#xff0c;当时程序员圈里就有个梗很火&#xff0c;说的是当时几种常用编程语言的鄙视链&#xff1a;做C的鄙视做Java的&#xff0c;做Java的鄙视做C#的&#xff0c;而我很不幸&#xff0c;当时在鄙视链最底层。一开始只是当个笑话听听就算了&#x…

MIB 6.1810实验Xv6 and Unix utilities(3)pingpong

Mit6.S081-实验1-Xv6 and Unix utilities-pingpong问题_Isana_Yashiro的博客-CSDN博客 Write a user-level program that uses xv6 system calls to ping-pong a byte between two processes over a pair of pipes, one for each direction. The parent should send a byte to…

00后如何组织双十一大促看这一篇就够了! | 京东云技术团队

引言 大家好&#xff0c;我是王蒙恩&#xff0c;一名“整顿职场”的00后。作为一名去年刚刚加入京东的校招生&#xff0c;我有幸成为本次CDP平台的11.11备战负责人。虽然早在实习的时候就经历过大促&#xff0c;但是真正组织整个部门的备战还是很难忘的。于是提起笔&#xff0…

深信服AC流量管理技术

拓扑图 一.保证通道针对修仙部&#xff0c;访问网站&#xff0c;邮件&#xff0c;DNS&#xff0c;IM&#xff0c;办工 OA&#xff0c;微博论坛网上银行等常见应用保证带宽最低 50%&#xff0c;最高 100% 1. 先新建线路带宽 2.新增流量管理通道&#xff08;保证关键应用&#x…

PPT基础:表格

目录 表格基本功能底纹框线单元格表格美化 表格基本功能 底纹 所在位置&#xff1a;插入图表>>>表设计>>>底纹 底纹&#xff1a;相当于每个单元格的“颜色填充”如何用表格拆分图片 &#xff08;1&#xff09;生成一个表格>>>插入一张图片>>…

我的创作纪念日——365天

机缘 最开始我写博客没有什么特别的原因&#xff0c;主要是因为以下几点&#xff1a; 练习自己的语言组织能力 记录自己学习生活中学到的知识 主要还是想找一个好的保存 Markdown 笔记的平台。 最终我选择了 CSDN&#xff0c;一来是因为 CSDN 对 Markdown 语法的支持较为全面…

计算机视觉的应用17-利用CrowdCountNet模型解决人群数量计算问题(pytorch搭建模型)

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用17-利用CrowdCountNet模型解决人群数量计算问题(pytorch搭建模型)。本篇文章&#xff0c;我将向大家展示如何使用CrowdCountNet这个神奇的工具&#xff0c;以及它是如何利用深度学习技术来解决复杂…

Taro.navigateTo 使用URL传参数和目标页面参数获取

文章目录 1. Taro.navigateTo 简介2. 通过 URL 传递参数3. 目标页面参数获取4. 拓展与分析4.1 拓展4.2 URL参数的类型4.3 页面间通信 5. 总结 &#x1f389;欢迎来到Java学习路线专栏~Taro.navigateTo 使用URL传参数和目标页面参数获取 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x…