C/C++ static关键字详解(最全解析,static是什么,static如何使用,static的常考面试题)

news2025/2/23 1:54:04

目录

一、前言

 二、static关键字是什么?

三、static关键字修饰的对象是什么? 

 四、C 语言中的 static

 🍎static的C用法

 🍉static的重点概念

 🍐static修饰局部变量

 💦static在修饰局部变量和函数的作用

 🍓static修饰全局变量和函数

💦static在修饰全局变量和函数的作用

 五、C++中的 static

 🍌static的C++用法

🍊static在C++中的重点概念

 💦静态成员为所有类对象所共享,不属于某个具体的实例

 💦静态成员变量必须在类外定义,定义时不添加static关键字

 💦静态成员函数没有隐藏的this指针,不能访问任何非静态成员

 💦访问静态成员变量的特殊方式

 💦静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

六、static面试题

七、static OJ面试题

八、共勉


一、前言

        static,中文意思是静态的,作为C/C++中常用关键字中的一个很重要的关键字,其中用法多样且复杂难以理解,用起来总是丈二和尚摸不着头脑,把我折磨的一头雾水(主要是博主很菜😂)。

        也许大家对于这些知识都是一知半解(除过一些大佬),没有真正的搞透澈,一问我都会(这就是我),但是真正引用的时候,就会出现很多问题,而且百度的时候,大部分都讲得不是很清楚,所以为了帮助大家解决这个问题(实际上是自己不会),在这里进行一个全面的static介绍和总结。

        本文将会循序渐进,先从C语言的static讲起,慢慢延申到C++,从易到难,每一步都会举一些通俗易懂的例子帮助大家理解(帮助自己理解,怕忘记😂),好了开始整活!

 二、static关键字是什么?

        static是 C/C++中的关键字之一,是常见的函数与变量(C++中还包括类)的修饰符,它常被用来控制变量的存储方式和作用范围。 在众多高级语言中都有其作为关键字或函数出现,所以这也是应当被程序员熟知其各种含义的一个单词

三、static关键字修饰的对象是什么? 

1.局部变量

2.全局变量

3.函数

 四、C 语言中的 static

 🍎static的C用法

    1️⃣: 修饰局部变量(称为静态局部变量)

    2️⃣: 修饰全局变量(称为静态全局变量)

    3️⃣: 修饰函数(称为静态函数)

 🍉static的重点概念

1️⃣:在函数中声明变量时, static 关键字指定变量只初始化一次,并在之后调用该函数时保留其状态。
2️⃣:在声明变量时,变量具有静态持续时间,并且除非您指定另一个值。
3️⃣ :在全局和/或命名空间范围 (在单个文件范围内声明变量或函数时) static 关键字指定变量或函数为内部链接,即外部文件无法引用该变量或函数。
4️⃣:static 关键字 没有赋值时,默认赋值为 0 

5️⃣:static修饰局部变量时,会改变局部变量的存储位置,从而使得局部变量的生命周期变长。

⭐:接下来,将重点讲解上面三个作用个五点概念的理解,和应用

 🍐static修饰局部变量

1️⃣:在函数中声明变量时, static 关键字指定变量只初始化一次,并在之后调用该函数时保留其状态。
5️⃣:static修饰局部变量时,会改变局部变量的存储位置,从而使得局部变量的生命周期变长。

接下来用们用一段代码来进行解析:

#include <stdio.h>
#include <stdlib.h>
void test()
{
    int x = 0;
	x++;
	printf("%d ", x);
}
int main()
{
    int i = 0;
	printf("%d\n", i);
	while (i < 10)
	{
		test();
		i++;
	}
	return 0;
}

        这段代码中每次调用test()函数时创建局部变量x赋值为 0,每次局部变量x出了test()函数后都会自行销毁。
        所以可以很容易得到输出结果为:1 1 1 1 1 1 1 1 1 1


        接着我们用上static关键字来修饰  test()函数中的局部变量 x

#include <stdio.h>
#include <stdlib.h>
void test()
{
    static int x = 0;
	x++;
	printf("%d ", x);
}
int main()
{
    int i = 0;
	while (i < 10)
	{
		test();
		i++;
	}
	return 0;
}

        输出结果变成了:1 2 3 4 5 6 7 8 9 10
        原因是static修饰了局部变量x,令局部变量x变成静态的,且只能初始化一次,使得每次test()函数结束时局部变量x都不销毁,再次进入test()函数时则保留原有数值运行,因此x++数值越来越大。

总结:

(1)static关键字修饰局部变量不改变作用域,但是生命周期变长。

(2)本质上,static关键字修饰局部变量,改变了局部变量的存储位置,因为存储位置的差异,使得执行效果不一样。普通的局部变量放在栈区,这种局部变量进入作用域创建,出作用域释放。局部变量被static修饰后成为静态局部变量,这种变量放在静态区,创建好后,直到程序结束后才释放。
 

4️⃣:static 关键字 没有赋值时,默认赋值为 0 


接下来用们用一段代码来进行解析:

int a;
int main()
{
	char str[10];
	printf("integer: %d; string: (begin)%s(end)\n", a, str);
	return 0;
}

        在这段代码中,我们并没有对全局变量 a 和字符串数组 str 进行赋值,所以在输出时会出现随机值的现象。所以很容易得到如下的结果:

输出:

integer: 0; string: (begin)烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫攼l(end)

⚠ 注意:a 输出为 0 是因为 此时 a 是全局变量,也存放在静态区,所以可以默认值为 0 .


        接着我们用上 static关键字 来修饰 全局变量 a 和字符串数组 str 

static int a;
int main()
{
	static char str[10];
	printf("integer: %d; string: (begin)%s(end)\n", a, str);
	return 0;
}

  输出:

integer: 0; string: (begin)(end)

       总结:

         static的另一个作用是默认初始化为0。其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘\0’;太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是 ‘\0’。
 

 💦static在修饰局部变量和函数的作用

 ⭐作用:

        保持变量内容的持久

  • static的第一个作用是保持变量内容的持久,即static变量中的记忆功能和全局生存期。
  • 存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。之后再次运行到含有 static 关键字的初始化语句时不会再执行该语句。共有两种变量存储在静态存储区:全局变量和 static 变量,只不过和全局变量比起来,static 可以控制变量的可见范围。

 🍓static修饰全局变量和函数

3️⃣ :在全局和/或命名空间范围 (在单个文件范围内声明变量或函数时) static 关键字指定变量或函数为内部链接,即外部文件无法引用该变量或函数。

        针对上面这个概念的理解我们一次来解析以下:
1. 首先说一下全局变量,全局变量的作用域十分的广,只要在一个源文件中定义后,这个程序中的所有源文件、对象以及函数都可以调用,生命周期更是贯穿整个程序。文件中的全局变量想要被另一个文件使用时就需要进行外部声明(以下用extern关键字进行声明)。-----也即是说全局变量既可以在源文件中使用,也可以在其他文件中使用(只需要使用extern外部链接以下即可)

2. static修饰全局变量和函数时,会改变全局变量和函数的链接属性-------变为只能在内部链接,从而使得全局变量的作用域变小。

  接着我们用代码进行解析:


首先,在Hello.c文件中定义一个全局变量 char a 和函数 PrintfHello(),之后在test.c文件中进行extern 进行外部链接,运行代码:


之后我们进入正题 在全局变量和函数之前用 static进行修饰,看看效果:


        会发现生成错误,无法解析外部符号a和PrintfHello()等,全局变量a和PrintfHello()不能被test.c文件调用了。所以我们可以很容易看出static修饰后让全局变量a和PrintfHello()的作用域变小了,令全局变量a和PrintfHello()无法被其他文件调用。

总结:

1. 全局变量和函数本身是具有外部链接属性的,在Hello.c文件中定义的全局变量和函数,在test.c文件中可以通过【链接】来使用;

2. 但如果全局变量被static修饰,那这个外部链接属性就会被修改成内部链接属性此时这个全局变量就只能在自己的源文件中使用;

💦static在修饰全局变量和函数的作用

⭐作用:
        如果加了 static,就会对其它源文件隐藏。例如在 a 和 printHello 的定义前加上 static,main.c 就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static 可以修饰函数和变量,将其对其他源文件隐藏起来,从而避免命名冲突。对于函数来讲,static 的作用仅限于该隐藏功能。

 五、C++中的 static

        本小节主要介绍在 C++中引入了面向对象的特性(类)之后,static关键字的一些用途。当然 C++ 是兼容 C 语言的,所以C语言中的 static 在C++中也是成立的

 🍌static的C++用法

 声明为static的类成员称为类的静态成员,分为如下两类:

  • 用static修饰的成员变量,称之为静态成员变量
  • 用static修饰的成员函数,称之为静态成员函数

静态的成员变量一定要在类外进行初始化

🍊static在C++中的重点概念

1️⃣:静态成员为所有类对象所共享,不属于某个具体的实例
2️⃣:静态成员变量必须在类外定义,定义时不添加static关键字
3️⃣:静态成员函数没有隐藏的this指针,不能访问任何非静态成员
4️⃣:访问静态成员变量的特殊方式

5️⃣:静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

⭐:接下来,将重点讲解上面三个作用个五点概念的理解,和应用

 💦静态成员为所有类对象所共享,不属于某个具体的实例

请看如下代码:

class A
{
private:
	static int _n;
	int _k;
	char _a;
};
int main()
{
	cout << sizeof(A) << endl; //8
	return 0;
}

        这里的运行结果为8,这里的计算规则是按照C语言那套计算结构体大小的规则。并没有把我静态成员变量_n考虑进去,因为静态成员变量属于整个类,是类的所以对象,所以静态变量成员不计入总大小。
 

 💦静态成员变量必须在类外定义,定义时不添加static关键字

class A
{
private:
	//声明
	static int _n;
	static int _k;
};
//定义
int A::_n = 0;
int A::_k = 0;

 💦静态成员函数没有隐藏的this指针,不能访问任何非静态成员

class A
{
public:
	static void Func()
	{
		cout << ret << endl;  // err错误,访问了非静态成员,因为无this指针
		cout << _k << endl; //正确
	}
private:
	//声明
	int ret = 0;
	static int _k;
};
//定义
int A::_k = 0;

 💦访问静态成员变量的特殊方式

当静态成员变量为公有时,可有如下三种进行访问:

  1. 通过对象.静态成员来访问
  2. 通过类名::静态成员来行访问
  3. 通过匿名对象突破类域进行访问
class A
{
public:
// 声明
	static int _k;
};
// 定义
int A::_k = 0;
int main()
{
	A a;
	cout << a._k << endl;  //通过对象.静态成员来访问
	cout << A::_k << endl; //通过类名::静态成员来行访问
	cout << A()._k << endl;//通过匿名对象突破类域进行访问
	return 0;
}

当静态成员变量变成私有时,可采用如下方式:

  1. 通过对象.静态成员函数来访问
  2. 通过类名::静态成员函数来行访问
  3. 通过匿名对象调用成员函数进行访问
class A
{
public:
	static int GetK()
	{
		return _k;
	}
private:
	static int _k;
};
int A::_k = 0;
int main()
{
	A a;
	cout << a.GetK() << endl; //通过对象.静态成员函数来访问
	cout << A::GetK() << endl;//通过类名::静态成员函数来行访问
	cout << A().GetK << endl; //通过匿名对象调用成员函数进行访问
	return 0;
}

 💦静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

  • 1、静态成员函数可以调用非静态成员函数吗?

答案:不可以,因为静态成员函数是没有this指针的,无法调用非静态成员函数。
 

  • 2、非静态成员函数可以调用类的静态成员函数吗?

答案:可以,因为静态成员为所有类对象所共享,不受访问限制
 

六、static面试题

搞清楚了static的特性,来看几道道面试题:

面试题1:

实现一个类,计算中程序中创建出了多少个类对象。

  • 思路:

假设命名该类为A,那么A类型的对象一定是经过构造函数或拷贝构造的,那么我们就可以分别定义两个静态成员变量,在构造函数和拷贝构造里++变量,这样,每创建一次对象,变量就++一次,自然就好求了。如下:

class A
{
public:
	A()
	{
		++_count1;
	}
	A(const A& aa)
	{
		++_count2;
	}
	static int GetCount1()
	{
		return _count1;
	}
	static int GetCount2()
	{
		return _count2;
	}
private:
	static int _count1; 
	static int _count2;
};
int A::_count1 = 0;
int A::_count2 = 0;
A Func(A a)
{
	A copy(a);
	return copy;
}
int main()
{
	A a1;
	A a2 = Func(a1);
 
	cout << a1.GetCount1() << endl; // 1
	cout << a2.GetCount2() << endl; // 3
	cout << A::GetCount1() + A::GetCount2() << endl; // 4
}
  • 分析:

        A a1 调用了一次构造函数;a2 = Func(a1),调用了一次拷贝构造;A copy(a),调用了一次拷贝构造;return copy 返回的时候,copy会销毁,所以提前需要进行拷贝构造进行拷贝保存 。所用总共四次。

七、static OJ面试题

 1、求1+2+3+...+n

  • 题目:

  • 链接直达:

 求1+2+3+...+n

  • 思路:

这里我可以自己单独定义一个Sum类,专门进行求和,我定义n个对象,它就会调用n次构造函数,此时就可以在构造函数内实现累加,为了实现累加,需要在Sum类里设定两个静态成员变量,因为静态成员属于整个类,以此确保每次访问的变量都是同一个,最后,返回累加的值即可。

  • 注意:

如若不支持变长数组,我们只能用new来完成,在获取返回的累加值时,可以单独在类内写个函数返回私有成员变量,该函数可以是静态成员函数,这样就可以指定类域去调用,不需要借助对象了。也可以借助友元。

  • 代码:
#include<iostream>
using namespace std;
class Sum
{
public:
    Sum() //构造函数内实现累加
    {
        _ret += _i;
        _i++;
    }
    int GetRet()  //static int GetRet() 也可以是静态成员函数
    {
        return _ret;  //返回获取的求和值
    }
private:
    //静态成员变量类内声明
    static int _i;
    static int _ret;
};
//静态成员变量类外定义
int Sum::_i = 1;
int Sum::_ret = 0;
class Solution {
public:
    int Sum_Solution(int n) {
        Sum a[n]; //支持变长数组可以这样写
        return a[1].GetRet(); //注意通过对象去调用成员函数
        //return Sum::GetRet();静态成员函数支持用类域访问
        /* 如若不支持变长数组,就用new来开辟n个空间
        Sum* ptr = new Sum[n];
        return ptr->GetRet(); 
        */
    }
};

八、共勉

         以下就是我对C/C++ static关键字的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对C++ 类和对象的理解,请持续关注我哦!!!  

 

 

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

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

相关文章

office2024下载详细安装教程

简单的说 Office 是一款由Microsoft 开发的一套办公软件&#xff0c;里面包含了常用的办公组件而其中就包含了Word、Excel、PowerPoint、Access等&#xff01; 并且office是目前最常用的一类办公软件&#xff0c;使用它可以解决日常生活和工作中遇到的很多问题。 熟练掌握offi…

FMC+DAM驱动LVGL刷屏

前提条件 使用FMC驱动LCD刷屏 LVGL移植 开启DMA 需要开启MEMTOMEMDMA。 开启MPU 有MPU时需要 使能I-cache D-cache时 使用DMA传输数据时要保证数据的完整行和准确性 修改代码 逻辑 等待DMA传输完成然后再刷屏。 修改 在DMA初始化函数中最后添加 注册DMA传输完成调用函…

《动态顺序表》的实现

目录 前言&#xff1a; 认识线性表&#xff1a; 关于顺序表 实现动态顺序表&#xff1a; 顺序表的动态存储定义&#xff1a; 初始化顺序表&#xff1a; 顺序表的销毁&#xff1a; 尾插&#xff1a; 判断是否需要扩容&#xff1a; 总代码&#xff1a; 头插&#xff1a…

树莓派结合Nginx,轻松搭建内网穿透服务实现远程访问内部站点

文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx&#xff08;发音为“engine-x”&#xff09;可以将您的树莓派变成一个强大的 Web 服务器&#xff0c;可以用于托管网站或 Web 应用程序。相比其他 Web 服务器&#xff0c;Ngi…

C++17中std::any的使用

类sdk:any提供类型安全的容器来存储任何类型的单个值。通俗地说&#xff0c;std::any是一个容器&#xff0c;可以在其中存储任何值(或用户数据)&#xff0c;而无需担心类型安全。void*的功能有限&#xff0c;仅存储指针类型&#xff0c;被视为不安全模式。std::any可以被视为vo…

C语言实现输出一行文字中最长单词

完整代码&#xff1a; // 输出一行文字中最长单词 #include<stdio.h>#define N 20int main(){char str[N];printf("请输入一行文字\n");gets(str);//最长字符串的长度int max0;//str数组的下标int i0;//记录最长字符串在数组中的位置int flag0;//记录每个单词…

【sosp2023论文分享】Ditto:一个弹性自适应分离式内存缓存系统

Ditto: An Elastic and Adaptive Memory-Disaggregated Caching System 摘要 Ditto首先提出了一个以客户端为中心的缓存框架,以在DM的计算池中高效地执行各种缓存算法,只依赖于远程内存访问。然后,Ditto采用了一种分布式自适应缓存方案,该方案基于多个缓存算法的实时性能自…

链式二叉树的基本操作和相关OJ题训练(建议收藏!!!)

&#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;数据结构&C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学习编程知识 链式二叉树基本操作 二叉树节点设置二叉…

FMC驱动LCD

硬件简介 主控&#xff1a;STM32H750 LCD屏幕为16位并口屏幕 CubeMX配置 chip select: 选择起始地址块号&#xff0c;ADDR[27:26] Memory type: 内存类型&#xff0c;选择LCD Interface LCD Register Select: 根据选择计算映射地址, FSNC_A[25] Data: 数据宽度 NOR/PSRAM ti…

RISC-V与RISC Zero zkVM的关系

1. 引言 本文基本结构为&#xff1a; 编程语言背景介绍RISC-V虚拟机作为zkVM电路为何选择RISC-V&#xff1f; 2. 编程语言背景介绍 高级编程语言不专门针对某个架构&#xff0c;其便于人类编写。高级编程语言代码&#xff0c;经编译器编译后&#xff0c;会生成针对专门某架…

Azure 机器学习 - 设置 AutoML 训练时序预测模型

目录 一、环境准备二、训练和验证数据三、配置试验支持的模型配置设置特征化步骤自定义特征化 四、可选配置频率和目标数据聚合启用深度学习目标滚动窗口聚合短时序处理非稳定时序检测和处理 五、运行试验六、用最佳模型进行预测用滚动预测评估模型精度预测未来 七、大规模预测…

网络基础扫盲--TCP/UDP

博客内容&#xff1a;TCP/UDP 文章目录 一、TCP与UDP二、tcp可靠性如何保证&#xff1f;1、三次握手2、TCP报头3、TCP四次挥手 一、TCP与UDP tcp与udp都是传输层的协议&#xff0c;用于数据的传输。 对于tcp而言数据的传输会比较可靠&#xff0c;主要依赖于tcp面向链接的&…

openGauss学习笔记-114 openGauss 数据库管理-设置安全策略-设置帐号有效期

文章目录 openGauss学习笔记-114 openGauss 数据库管理-设置安全策略-设置帐号有效期114.1 注意事项114.2 操作步骤 openGauss学习笔记-114 openGauss 数据库管理-设置安全策略-设置帐号有效期 114.1 注意事项 创建新用户时&#xff0c;需要限制用户的操作期限&#xff08;有…

Prompt 设计与大语言模型微调,没有比这篇更详细的了吧!

本文主要介绍了Prompt设计、大语言模型SFT和LLM在手机天猫AI导购助理项目应用。 ChatGPT基本原理 “会说话的AI”&#xff0c;“智能体” 简单概括成以下几个步骤&#xff1a; 预处理文本&#xff1a;ChatGPT的输入文本需要进行预处理。 输入编码&#xff1a;ChatGPT将经过预…

如何使用Python和matplotlib绘制机器人运动偏差路径图——实用教程与代码解析

前言 科研论文中需要绘制一个精美的机器人运动路径图&#xff08;其中包含了机器人的期望运动路径和实际运动路径&#xff09;。我的期望路径是是一个方形&#xff0c;用Python代码是这样表示的&#xff1a; n_list [n1,n2,n3,n4] e_list [e1,e2,e3,e4] #n_list和e_list的各…

C++笔记之动态数组的申请和手动实现一个简单的vector

C笔记之动态数组的申请和手动实现一个简单的vector code review! 文章目录 C笔记之动态数组的申请和手动实现一个简单的vector1.C语言中动态数组的申请与使用1.动态数组的申请使用new和delete使用std::vector 1.std::vector的底层实现2.手动实现一个简单的vector:使用一个指向…

项目实战:展示第一页数据

1、在FruitDao接口中添加查询第一页数据和查询总记录条数 package com.csdn.fruit.dao; import com.csdn.fruit.pojo.Fruit; import java.util.List; //dao &#xff1a;Data Access Object 数据访问对象 //接口设计 public interface FruitDao {void addFruit(Fruit fruit);vo…

文件复制加密、文件落地加密、文件移动加密如何设置?

文件加密在保护信息安全方面具有重要作用。合格、好用的文件加密软件可以帮助企业保护商业机密、更遵守法律法规、提高企业核心竞争力、防止数据泄密等。 一般的加密都是对文件本身加密&#xff0c;比如加密某个WORD /PPT之类的&#xff0c;很少有能够加密某个文件夹的。今天就…

单链表基本操作的实现,初始化,头插,尾插,判空,获取个数,查找,删除,获取前置和后置位,清空,销毁

目录 一.单链表的设计 二.单链表的实现 三.单链表的总结 一.单链表的设计 1.单链表的结构定义: typedef struct Node{int data;//数据域struct Node* next;//后继指针}Node,*List; 2.单链表的设计示意图: 3.注意,单链表的最后一个节点的next域为NULL; 4.为什么要有一个头…

唯一ID如何生成,介绍一下目前技术领域最常使用的几种方法

纵使十面大山&#xff0c;又如何&#xff0c;无妨… 概述 唯一ID&#xff08;Unique Identifier&#xff09;是在计算机科学和信息技术领域中用于标识某个实体或数据的唯一标识符。生成唯一ID的方法可以根据具体需求和应用场景的不同而有所不同。以下是一些目前技术领域中常用…