[C++基础] 变量、关键字、运算符、位操作篇

一、变量篇

1 全局变量和静态变量有什么异同?

相同:都在静态存储区分配空间,生命周期与程序生命周期相同。
**区别:**全局变量的作用域是整个程序,它只需要在一个源文件中定义,就可以作用于所有的源文件。而静态变量只在定义其的源文件内有效。

2 变量定义与变量声明有什么区别?

定义(definition)为变量分配存储空间,还可以为变量指定初始值。而声明(declaration)是指向程序表明变量的类型和名字。 定义也是声明,定义变量的同时也声明了它的类型和名字。一般为了叙述方便,把建立存储空间的声明称定义,而不把建立存储空间的声明称为声明。

3 C 语言中各种变量的默认初始值是什么?

全局变量放在内存的全局数据区,如果在定义的时候不初始化,则系统将自动为其初始化,数值型为0,字符型为空,指针变量也被赋值为NULL。静态变量的情况与全局变量类似。而非静态局部变量如果不显示初始化,那么其内容是不可预料的,将是随机数,会很危险,对系统的安全造成非常大的隐患。

4 如何判断一段程序是 C 编译程序还是 C++ 编译程序编译的?

如果编译器在编译 cpp 文件,那么 _cplusplus 就会被定义,如果是一个 C 文件在被编译, 那么 STDC 就会被定义。STDC 是预定义宏,当它被定义后,编译器将按照 ANSIC 标准来编译 C 语言程序。所以可以采用如下程序进行判断:

#ifdef _cplusplus
#define USING_CPP 1
#else
#define USING_CPP 0
#endif#include <stdio.h>int main()
{if(USING_CPP)printf("C++\n");elseprintf("C\n");return 0;
}

5 C 语言中 int 和 float 有什么区别?

主要有如下三个区别:

(1)表示的数据范围不同。C 语言中的 int 变量通常的表示范围为-2147483648~2147483647,也就是-231到231之间。而-3.4E+38 ~ 3.4E+38则是 float 类型表示的数据范围。float 表示的数据范围要大于 int 表示的数据范围。

(2)变量赋值方法不同。C 语言中,将 i 设定为一个 int 变量并赋值的方法为:int i=xx;,其中 xx 为一个整数,例如 3、4、5,不可以是小数。将 i 设定为一个 float 变量的方法为:float i=yy;,其中 yy 为一个浮点型数,可以带上小数点,例如 3.0、4.5、5.7 等等。

(3) 字节构成不同。int 和 float 类型在计算机中都占 4 个字节,但是 float 类型的 4 个字节构成为包括一个符号位、一个 8 位二进制指数和一个 23 位尾数, 以指数形式存储,而 int 类型的 4 个字节构成全部为整数。
扩展: 为什么有些int是float表示不了的呢?
因为 int 与 float 同样占4个字节,float 表示的范围又比 int 大并且还包含很多小数,那 int 的每个值都能被 float 表示就是不可能的事情了。

6 int为什么在32位系统中是4个字节?

32 位系统对应的 CPU 是32位的,为了和 CPU 的字宽一致,提高处理速度。

7 为什么一个指针在32位系统中占4个字节,在64位系统中占8个字节?

可以参考:
为什么一个指针在32位系统中占4个字节,在64位系统中占8个字节?

二、C/C++ 关键字

1 const 有哪些作用?

(1)定义常量,使其值不可被修改,另外使编译器可以对其进行类型检查;
(2)修饰函数形参,防止值被意外的修改,提高程序的健壮性;
(3)修饰函数返回值,使返回值不能被修改;
(4)修饰常量指针(const char *p)和指针常量(char * const p);
(5)在 C++ 中,修饰类成员函数,任何不会修改数据成员的函数都应该用 const 修改,以及修饰类成员数据。

2 extern 有哪些作用?

extern 有两种作用,下面分别详细介绍一下。
1. 在模块外使用全局变量
extern 可以置于变量或者函数前,如在头文件中:extern int g_val;,其声明的函数和变量可以在其他模块中使用,记住它是一个声明不是定义。也就是说 B 模块(编译单元)要是引用模块(编译单元) A 中定义的全局变量或函数时,它只要包含 A 模块的头文件即可。
2. 在 C++ 环境下使用 C 函数
C++ 语言是一种面向对象编程语言,支持函数重载,而 C 语言是面向过程的编程语言, 不支持函数重载,所以函数被 C++ 编译后在库中的名字与 C 语言的不同。如果声明一个 C 语言函数float f(int a,char b),C++ 的编译器就会将这个名字变成像 _f_int_char 之类的东西以支持函数重载。然而 C 语言编译器的库一般不执行该转换,所以它的内部名为 _f,这样连接器将无法解释 C++ 对函数 f() 的调用。

C++ 提供了 C 语言符号extern “C”来解决名字匹配问题,extern 后跟一个字符串来指定想声明的函数的连接类型,后面是函数声明。

extern "C" float f(int a,char b);

该语句的目的是告诉编译器 f() 是 C 连接的,这样 C++ 就不会转换函数名。应该到库中找名字 _f 而不是找 _f_int_char。 C++ 编译器开发商已经对 C 标准库的头文件作了 extern “C” 处理,所以可以用 include 直接引用这些头文件。
3 static 变量有哪些作用?
(1)在函数体内,被声明为静态的变量只初始化一次,以后该函数再被调用,将不会再初始化,这就使变量具有 “记忆” 功能。

(2)在模块内(但在函数体外),如果把一个变量或者函数声明为静态的,那么可以将其作用域被限制在本模块内,起一个 “隐藏” 的作用,避免命名冲突。

(3)默认初始化为 0,因为静态变量存储在静态数据区,而静态数据区中的所有字节默认值都是 0,某些时候这一特点可以减少程序员的工作量。比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加 ‘\0’ 太麻烦。如果把字符数组定义成静态的,就省去了这个麻烦。(全局变量也存储在静态数据区)

(4)在 C++ 中,在类中声明 static 变量或者函数。其初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员,这样就出现以下作用:
类的静态成员函数是属于整个类而非类的对象,所以它没有 this 指针,这就导致了它仅能访问类的静态数据和静态成员函数;
不能将静态成员函数定义为虚函数;
由于静态成员函数没有 this 指针,所以就差不多等同于 nonmember 函数,结果就产生了一个意想不到的好处:成为一个 callback 函数,使得我们得以将 C++ 和 C-based X Window 系统结合,同时也成功的应用于线程函数身上。
4 new/delete 与 malloc/free 的区别是什么?
(1)new/delete 是操作符,而 malloc/free 是函数,在C语言中需要 <stdlib.h> 的支持;
(2)new 能够自动计算需要分配的内存空间,而 malloc 需要手工计算字节数;
(3)new 与 delete 直接带具体类型的指针,而 malloc 与 free 返回的是 void 类型的指针;
(4)new 是类型安全的,而 malloc 不是,例如int* p = new float[2],编译时就会报错; 而int* p = malloc(2 * sizeof(float)),编译时编译器就无法指出错误来;
(5)new 将调用构造函数,而 malloc 不能;delete 将调用析构函数,而 free 不能。
5 断言 ASSERT() 是什么?
ASSERT() —般被称为断言,它是一个调试程序时经常使用的宏。它定义在 <assert.h> 头文件中,通常用于判断程序中是否出现了非法的数据,在程序运行时它计算括号内的表达式的值。如果表达式的值为 false(0),程序报告错误,终止运行,以免导致严重后果,同时也便于查找错误;如果表达式的值不为 0,则继续执行后面语句。其用法如下:

ASSERT(n != 0); // 分母为0,为非法数据,表达式为false,程序报告错误,程序会终止运行
k = 10 / n;

需要注意的是,ASSERT()只在 Debug 版本中有,编译的 Release 版本则被忽略。还需要注意的一个问题是 ASSERT() 与 assert() 的区别,ASSERT() 是宏,而 assert() 是ANSI C标准中规定的函数,它与 ASSERT() 的功能类似,但是可以应用在 Release 版本中。

三、C/C++ 运算符

1 前置运算与后置运算有什么区别?
以 ++ 操作为例,对于变量 a, ++a 表示先增加内存中 a 的值,然后再把值放在装入寄存器中;a++ 表示先把 a 的值装入寄存器,然后再增加内存中 a 的值。

一般而言,当涉及表达式计算时,++a 是先将值增加 1,再返回其值;而 a++ 是先返回其值,再增加1。
2 a是变量,执行 (a++) += a 语句是否合法?
不合法。a++ 不能当做左值使用。++a 可以当左值使用。a++ 是先把a的值装入寄存器,然后再增加内存中 a 的值,此时左值是 a 的值,而值不能作为左值,所以非法。而 ++a 是先增加内存中 a 的值,然后再把值放在装入寄存器中,此时左值是 a,所以合法。

**3 p++与(p)++等价吗?为什么?
因为优先级顺序的问题,*p++与(*p)++并不等价,前者先完成取值操作,然后对指针地址执行 ++ 操作;而后者先完成取值操作,然后对该值进行 ++ 运算

四、位操作

.1 一些结构声明中的冒号和数字是什么意思?
C 语言的结构体可以实现位段,它的定义形式是在一个定义的结构体成员后面加上冒号, 然后是该成员所占的位数。位段的结构体成员必须是 int 或者 unsigned int 类型,不能是其他类型。位段在内存中的存储方式是由具体的编译器决定的。
示例程序如下:

#include <stdio.h> typedef struct
{int a:2; int b:2; int c:l;
}test;int main()
{test t; t.a = 1; t.b = 3; t.c = 1;printf("%d %d %d %d\n",t.a, t.b, t.c, sizeof(test)); // 1 -1 -1 4return 0;
}

由于 a 占两位,而 a 被赋值为 1,二进制就是 01,因此 %d 输出的时候输出 1;b 也占了两位,赋值为 3,二进制也就是 11,由于使用了 %d 输出,表示的是将这个 b 作为有符号 int 型来输出,这样的话二进制的 11 将会有一位被认为是符号位,并且两位的 b 也会被扩展为 int 类 型,也就是4字节,即 32 位。
1.2 如何实现位操作求两个数的平均值?
一般而言,求解平均数的方法就是将两者相加,然后除以 2,以变量 x 与 y 为例,两者的平均数为 (x+y)/2。

但是采用上述方法,会存在一个问题,当两个数比较大时,如两者的和大于了机器位数能够表示的最大值,可能会存在数据溢出的情况,而采用位运算方法则可以避免这一问题,而且位运算相比除法运算, 效率更高。
示例程序如下:

#include <stdio.h>int main()
{int x = 2147483647, y = 2147483647;printf("%d\n",(x+y)/2); // -1printf("%d\n",(x&y)+((x^y)>>1)); //  2147483647return 0;
}

1.3 如何求解整型数的二进制表示中 1 的个数?
方法一,程序代码如下:

#include <stdio.h> int func (int n)
{int count=0; 	while (n){count += n & 0x1u ;n >>= 1 ;}return count;
}int main()
{printf("%d\n",func(9999)); // 8 return 0;
}

判断每个数的二进制表示中每一位是否为 1,如果为 1,就在 count 上加 1,而循环的次数是常数,即 n 的位数。但该方法有一个缺陷,就是在 1 比较稀疏的时候效率会比较低。
方法二,程序代码如下:

#include <stdio.h> int func(int x)
{int countx = 0; while(x){countx++; x = x&(x-1);}return countx;
}int main()
{printf("%d\n", func(9999)); // 8return 0;
}

为了理解这个算法的核心,需要理解以下两个操作:

(1)当一个数被减 1 时,它最右边的那个值为 1 的 bit 将变为 0,同时其右边的所有的 bit 都会变成 1;

(2)“&=”,位与并赋值操作。去掉已经被计数过的 1,并将该值重新设置给 n。这个算法循环的次数是 bit 位为 1 的个数,对 bit 为 1 比较稀疏的数来说,性能很好。

1.4 不能用 sizeof() 函数,如何判断操作系统是 16 位还是 32 位的?
方法一:一般而言,机器位数不同,其表示的数字的最大值也不同,根据这一特性,可以判断操作系统的位数。例如,运行如下代码:

#include <stdio.h> int main()
{int i = 65536; printf("%d\n",i); // 16位机器下输出0,32位机器下输出65536int j = 65535; printf("%d\n",j); // 16位机器下输出-1,32位机器下输出65535return 0;
}

由于 16 位机器下,能够表示的最大数为65535,会出现越界情况。而在 32 位机器下,则不会出现溢出的情况,所以输出为正常输出。
方法二:对 0 值取反,不同位数下的 0 值取反,其结果不一样。运行如下代码:

#include <stdio.h> int main()
{unsigned int a =0; if( a>65536)printf("32 位\11");elseprintf(16 位\11"); return 0;
}

1.5 嵌人式编程中,什么是大端?什么是小端?
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。

大小端在内存中的存放方式举例
一个 16bit 的 short 型 x,在内存中的地址为 0x0010,x 的值为 0x1122。那么 0x11 为数据高字节,0x22 为数据低字节。

对于大端模式,就将 0x11 放在内存低地址中,即 0x0010 中;0x22 放在内存高地址中,即 0x0011 中。
小端模式,就将 0x11 放在内存高地址中,即 0x0011 中;0x22 放在内存低地址中,即 0x0010 中。
我们常用的 X86 结构是小端模式,而 KEIL C51 则为大端模式。很多的 ARM,DSP 都为小端模式。有些 ARM 处理器还可以由硬件来选择是大端模式还是小端模式。
引申:如何判断计算机处理器是大端还是小端?
方法一:可以通过指针地址来判断,由于在32位计算机系统中,int 占 4 个字节,char 占 1 个 字节,所以可以采用如下做法实现该判断。

int fun()
{int num = 0x12345678;// (char*)&num获得num的起始地址,*((char*)&num)是num的起始地址所指向的值。return*((char*)&num) == 0x12 )?1:0; // 本机返回1,为大端 返回0,为小端
}

方法二:联合体union的存放顺序是所有成员都从低地址开始存放。

// 判断系统是大端还是小端:通过联合体,因为联合体的所有成员都从低地址开始存放
int fun()
{union test{int i;char c;};test t;t.i = 1;// 如果是大端,则t.c为0x00,则t.c!=1,返回0 是小端,则t.c为0x01,则t.c==1,返回1return (t.c == 1);
}

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

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

相关文章

Vulnhub实战-prime1

前言 VulnHub 是一个面向信息安全爱好者和专业人士的虚拟机&#xff08;VM&#xff09;漏洞测试平台。它提供了一系列特制的漏洞测试虚拟机镜像&#xff0c;供用户通过攻击和漏洞利用的练习来提升自己的安全技能。本次&#xff0c;我们本次测试的是prime1。 一、主机发现和端…

写一篇nginx配置指南

nginx.conf配置 找到Nginx的安装目录下的nginx.conf文件&#xff0c;该文件负责Nginx的基础功能配置。 配置文件概述 Nginx的主配置文件(conf/nginx.conf)按以下结构组织&#xff1a; 配置块功能描述全局块与Nginx运行相关的全局设置events块与网络连接有关的设置http块代理…

Android Fragment

基本概念 Fragment是Android3.0后引入的一个新的API&#xff0c;他出现的初衷是为了适应大屏幕的平板电脑&#xff0c; 普通手机开发也会加入这个Fragment&#xff0c; 可以把他看成一个小型的Activity&#xff0c;又称Activity片段&#xff01; 如果一个很大的界面&#xff…

改进YOLOv5小目标检测:构建多尺度骨干和特征增强模块,提升小目标检测

构建多尺度骨干和特征增强模块,提升小目标检测 背景代码使用配置文件如下🔥🔥🔥 提升小目标检测,创新提升 🔥🔥🔥 测试在小目标数据集进行提点 👉👉👉: 新设计的创新想法,包含详细的代码和说明,具备有效的创新组合 🐤🐤🐤 1. 本文包含两个创新改…

[.NET 6] IHostedService 的呼叫等等我的爱——等待Web应用准备就绪

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不是技术而是人心,人心不可测,海水不可量,唯有技术,才是深沉黑夜中的一座闪烁的灯塔 !序言 在这篇文章中,我将介绍如何等…

C语言练习题解析(2)

&#x1f493;博客主页&#xff1a;江池俊的博客⏩收录专栏&#xff1a;C语言刷题专栏&#x1f449;专栏推荐&#xff1a;✅C语言初阶之路 ✅C语言进阶之路&#x1f4bb;代码仓库&#xff1a;江池俊的代码仓库&#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐ 文…

[论文阅读]Coordinate Attention for Efficient Mobile Network Design

摘要 最近关于移动网络设计的研究已经证明了通道注意力(例如&#xff0c; the Squeeze-and-Excitation attention)对于提高模型的性能有显著的效果&#xff0c;但它们通常忽略了位置信息&#xff0c;而位置信息对于生成空间选择性注意图非常重要。在本文中&#xff0c;我们提出…

基于SpringbootShiro实现的CAS单点登录

概述 单点登录&#xff08;Single Sign On,SSO&#xff09;是一种登录管理机制&#xff0c;主要用于多系统集成&#xff0c;即在多个系统中&#xff0c;用户只需要到一个中央服务器登录一次即可访问这些系统中的任何一个&#xff0c;无须多次登录。常见的例子就是&#xff0c;…

Redis缓存

1. Redis缓存相关问题 1.1 缓存穿透 缓存穿透是指查询一个数据库一定不存在的数据。 我们以前正常的使用Redis缓存的流程大致是&#xff1a; 1、数据查询首先进行缓存查询 2、如果数据存在则直接返回缓存数据 3、如果数据不存在&#xff0c;就对数据库进行查询&#xff0…

企业级数据仓库-数仓实战

数仓实战 安装包大小 安装清单 环境搭建 一、环境搭建01&#xff08;机器准备&#xff09; 准备好三台虚拟机&#xff0c;并进行修改hostname、在hosts文件增加ip地址和主机名映射 。 1、设置每个虚拟机的hostname vi /etc/sysconfig/network 修改HOSTNAMEnode02修改hostna…

Llama2-Chinese项目:2.2-大语言模型词表扩充

因为原生LLaMA对中文的支持很弱&#xff0c;一个中文汉子往往被切分成多个token&#xff0c;因此需要对其进行中文词表扩展。思路通常是在中文语料库上训练一个中文tokenizer模型&#xff0c;然后将中文tokenizer与LLaMA原生tokenizer进行合并&#xff0c;最终得到一个扩展后的…

Docker网络学习

文章目录 Docker容器网络1.Docker为什么需要网络管理2. Docker网络简介3. 常见的网络类型4. docker 网络管理命令5.两种网络加入差异6.网络讲解docker Bridge 网络docker Host 网络docker Container 网络docker none 网络 Docker容器网络 1.Docker为什么需要网络管理 容器的网…

自动生成bug异常追踪-SRE与开发自动化协同

作者&#xff1a;观测云 数据智能部 产品方案架构师 范莹莹 简介 生产环境 bug 的定义&#xff1a;RUM 应用和 APM 应用的 error_stack 信息被捕捉后成为 bug。 以 APM 新增错误巡检为例&#xff0c;当出现新错误时&#xff0c;在观测云控制台的「事件」模块下生成新的事件报…

基于matlab实现的电力系统稳定性分析摆幅曲线代码

完整程序&#xff1a; clear; clc; t 0; tf 0; tfl 0.5; tc 0.5; % tc 0.05, 0.125, 0.5 sec for 2.5 cycles, 6.25 cycles & 25 cycles resp ts 0.05; m 2.52 / (180 * 50); i 2; dt 21.64 * pi / 180; ddt 0; time(1) 0; ang(1) 21.64; pm 0.9; pm1 2.44;…

java 字符串只保留数字、字母、中文

public static void main(String[] args) {String str "测 试 WG23-D";// 只留字母String s1 str.replaceAll("[^a-zA-Z]", "");// 只留数字String s2 str.replaceAll("[^0-9]", "");// 只留中文String s3 str.replaceA…

骨传导耳机有害处吗、骨传导耳机真的不好用吗?

骨传导耳机没有害处。 骨传导耳机是通过将声音传递到颅骨&#xff0c;再由颅骨传递到内耳&#xff0c;从而达到听声音的效果&#xff0c;与传统的耳机不同。 因此&#xff0c;骨传导耳机不会直接对人的身体健康、耳朵产生压力和损伤&#xff0c;也不会影响耳道和中耳的正常功能…

Jmeter性能实战之分布式压测

分布式执行原理 1、JMeter分布式测试时&#xff0c;选择其中一台作为调度机(master)&#xff0c;其它机器作为执行机(slave)。 2、执行时&#xff0c;master会把脚本发送到每台slave上&#xff0c;slave 拿到脚本后就开始执行&#xff0c;slave执行时不需要启动GUI&#xff0…

题目 1057: 二级C语言-分段函数

有一个函数如下&#xff0c;写一程序&#xff0c;输入x&#xff0c;输出y值。 保留两位小数 样例输入 1 样例输出 1.00 这道题的思路很简单&#xff0c;我直接用if判断输入的X对应的函数Y的区间&#xff0c;代入对应的函数&#xff0c;求出结果。记得变量用浮点型&#xff…

【毕设选题】opencv 图像识别 指纹识别 - python

文章目录 0 前言1 课题背景2 效果展示3 具体实现3.1 图像对比过滤3.2 图像二值化3.3 图像侵蚀细化3.4 图像增强3.5 特征点检测 4 OpenCV5 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往…

计算机竞赛 机器视觉的试卷批改系统 - opencv python 视觉识别

文章目录 0 简介1 项目背景2 项目目的3 系统设计3.1 目标对象3.2 系统架构3.3 软件设计方案 4 图像预处理4.1 灰度二值化4.2 形态学处理4.3 算式提取4.4 倾斜校正4.5 字符分割 5 字符识别5.1 支持向量机原理5.2 基于SVM的字符识别5.3 SVM算法实现 6 算法测试7 系统实现8 最后 0…