188. 总结static的应用和作用
- 函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值。
- 在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其他函数访问。
- 在模块内的static函数只可被这一模块的其他函数调用,这个函数的适用范围被限制在声明它的模块内。
- 在类中的static成员变量属于整个类所拥有,对类的对象只有一份拷贝
- 在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。
189. 总结const的应用和作用
- 欲阻止一个变量被改变,可以使用const关键字。在定义const变量时,通常需要对它初始化,因为以后就没有机会去改变他了。
- 对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const。
- 在一个函数声明中,const可以修饰形参,表明他是一个输入参数,在函数内部不能改变其值
- 对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量
- 对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。
190. 什么是指针?谈谈你对指针的理解。
- 指针是一个变量,该变量专门存放内存地址。
- 指针变量的类型取决于其指向的数据类型,在所指数据类型前加*。
- 指针变量的特点是他可以访问所指向的内存。
191. 什么是常指针?什么是指向常变量的指针?
常指针的含义是该指针所指向的地址不能改变,但该地址所指向的内容可以变化,使用常指针可以保证我们的指针不能指向其他变量。
指向常变量的指针是指该指针的变量本身的地址可以发生变化,可以指向其他的变量,但是他所指的内容不可以被修改。
192. 函数指针和指针函数的区别?
函数指针是指向一个函数入口的指针;
指针函数是函数的返回值是一个指针类型。
193. 简述Debug版本和Release版本的区别?
Debug
版本是调试版本,Release
版本是发布给用户的最终非调试版本。
194. 指针的几种典型应用情况
int *p[n]
—— 指针数组,每个元素均为指向整形数据的指针。int (*)p[n]
——p为指向一维数组的指针,这个一维数组有n个整型数据。int *p()
——函数带回指针,指针指向返回的值。int (*)p()
——p为指向函数的指针。
195. static函数与普通函数有什么区别?
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝。
196. struct(结构)和union(联合)的区别?
struct
和union
都是由多youdao个不同的数据类型的成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。- 对于
union
的不同成员赋值,将会对其他成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值时互不影响的。
解释:
结构体 (struct
)
- 存储:结构体中的所有成员都有自己的独立存储空间。每个成员的地址相对于结构体变量的基地址是固定的,并且所有成员可以同时存在。
- 成员访问:访问结构体的不同成员之间互不影响。例如,如果你向一个成员赋值,这个操作不会影响其他成员的值。
#include <stdio.h>struct ExampleStruct {int integer;float decimal;char character;
};int main() {struct ExampleStruct s;s.integer = 10;s.decimal = 3.14;s.character = 'A';printf("integer: %d\n", s.integer); // 输出: integer: 10printf("decimal: %f\n", s.decimal); // 输出: decimal: 3.140000printf("character: %c\n", s.character); // 输出: character: Areturn 0;
}
在这个例子中,ExampleStruct
结构体中的三个成员 integer
、decimal
和 character
拥有独立的存储空间,互不影响。
联合体 (union
)
- 存储:联合体的所有成员共享同一块存储空间。这意味着在任何给定时间,联合体只能存储其中一个成员的值。联合体的大小是它最大成员的大小。
- 成员访问:当你给联合体的一个成员赋值时,这个值会影响其他成员,因为所有成员共享同一块存储空间。仅最后赋的值会被保存。
#include <stdio.h>union ExampleUnion {int integer;float decimal;char character;
};int main() {union ExampleUnion u;u.integer = 10;printf("integer: %d\n", u.integer); // 输出: integer: 10u.decimal = 3.14;printf("decimal: %f\n", u.decimal); // 输出: decimal: 3.140000printf("integer: %d\n", u.integer); // 可能会输出一个不可预测的值,因为它已经被覆盖printf("character: %c\n", u.character); // 可能会输出随机字符,因为它已经被覆盖u.character = 'A';printf("character: %c\n", u.character); // 输出: character: Aprintf("decimal: %f\n", u.decimal); // 可能会输出一个不可预测的值,因为它已经被覆盖return 0;
}
在这个例子中,ExampleUnion
联合体中的三个成员 integer
、decimal
和 character
共享同一个存储空间。当你改变其中一个成员的值时,其他成员的值会被覆盖且不可预测。
关键区别总结:
-
存储空间:
struct
中每个成员都有自己独立的存储空间,因此可以同时存在。union
中所有成员共享同一个存储空间,因此在任何一个时间点只能存储一个成员的值。
-
成员间的关系:
- 在
struct
中,修改一个成员的值不会影响其他成员。 - 在
union
中,修改一个成员的值会影响其他成员,因为所有成员存储在同一块内存中。
- 在
-
用途:
struct
通常用于需要同时保存多个不同类型的数据的场景。union
通常用于需要在不同时间存储不同类型但不需要同时保存不同类型数据的场景,例如保存一个值的不同视图或表示方式。
扩展理解:
-
大小:
- 一个
struct
的大小是所有成员大小之和,可能还包括内存对齐导致的间隙。 - 一个
union
的大小是其最大成员的大小,因为所有成员共用一块内存。
- 一个
-
内存对齐:
- 结构体成员是按照定义顺序排列的,通常需要考虑内存对齐的问题以提高访问效率。
- 联合体的所有成员从同一内存地址开始,不存在内存对齐间隙的问题。
197. class 和 struct 的区别?
struct 的成员默认是公有的,而类的成员默认是私有的。
198. 简述枚举类型
枚举方便一次定义一组常量,使用起来很方便。
解释:
简述
枚举类型,是编程语言(如C、C++、Java, Python等)中的一种数据类型,允许开发者定义一组命名的整数常量。这些常量被称为枚举成员,每个枚举成员隐式地对应一个整数值。
解释
- 定义固定值:枚举方便一次定义一组相关的常量,类似于有意义的标签,便于代码的阅读和维护。
- 提高代码可读性:使用枚举可以避免魔法数(magic numbers),这些常量在代码中有清晰的名称,增强了可读性和可维护性。
- 便于管理:集中管理这些常量,增加新值或修改现有值时,只需在枚举定义中进行修改,减少了疏漏和出错的机会。
示例
C 语言
#include <stdio.h>// 定义一个枚举类型
enum Day {SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY
};int main() {enum Day today = WEDNESDAY;printf("Today is: %d\n", today); // 输出: Today is: 3return 0;
}
在这个例子中, Day
枚举定义了一个一周的天数,每个枚举成员都隐式地被赋值为一个整数,从0开始(SUNDAY是0,MONDAY是1,依次类推)。
Java 语言
public class EnumExample {// 定义一个枚举类型enum Day {SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}public static void main(String[] args) {Day today = Day.WEDNESDAY;System.out.println("Today is: " + today); // 输出: Today is: WEDNESDAY}
}
Java 的枚举更加强大,它不仅仅是整数常量,还可以定义字段、方法等,像类一样使用。
补充
- 默认值与自定义值:
- 在C语言中,枚举成员从0开始递增,你也可以手动为枚举成员指定值。例如:
enum Day {SUNDAY = 1,MONDAY,TUESDAY = 5,WEDNESDAY,THURSDAY,FRIDAY = 10,SATURDAY};// MONDAY = 2, WEDNESDAY = 6, THURSDAY = 7, SATURDAY = 11
- 在这种情况下,后续未指定值的成员将按之前的值递增。
-
作用域与类型安全:
- 在 C 语言中,枚举成员在编译时期被替换为整数值,具有相同作用域但不严格的类型检查。
- 在 Java 中,枚举是一个真正的类类型,具有类型安全和严格的作用域管理。
-
扩展功能:
- 高级语言中的枚举(如 Java 和 C#)可以包含字段、方法,可以实现接口。
- 可以为枚举添加构造函数、属性以及方法,甚至使用枚举实现一些设计模式,如单例模式。
-
应用场景:
- 枚举常用于定义一组相关但有限的常量值集,如一周的天数、月份、状态码、颜色等等。
- 在状态机实现、资源标识(如HTTP状态码)等需要预定义一组固定值的地方,枚举是一种非常方便的选择。
总结
枚举类型是一种便捷的方式来定义常量集合,便于后续代码的使用、维护和阅读。通过使用枚举,能有效避免魔法数,提高程序的可读性和可靠性,并在一定程度上帮助实现类型安全。
这里 , “魔法数”(magic number)在编程中指的是直接在代码中使用的具体数字常量,这些数字通常没有明显的意义或解释。使用魔法数会降低代码的可读性和可维护性,因为它们不直观,不能清晰地表达其在程序中的作用或含义。
魔法数的例子
假设有一段代码如下:
int calculateBonus(int level) {if (level == 1) {return 500;} else if (level == 2) {return 1000;} else if (level == 3) {return 1500;}return 0;
}
在这段代码中,1
、2
、3
、500
、1000
和 1500
都是魔法数。它们的含义不清晰,读者无法通过代码直接了解这些数字的具体意义。
使用枚举和常量来避免魔法数
通过使用枚举和常量,可以提高代码的可读性和可维护性。重写上述代码,使用枚举类型和常量:
enum Level {BEGINNER = 1,INTERMEDIATE = 2,ADVANCED = 3
};const int BEGINNER_BONUS = 500;
const int INTERMEDIATE_BONUS = 1000;
const int ADVANCED_BONUS = 1500;int calculateBonus(Level level) {switch(level) {case BEGINNER:return BEGINNER_BONUS;case INTERMEDIATE:return INTERMEDIATE_BONUS;case ADVANCED:return ADVANCED_BONUS;default:return 0;}
}
好处
-
可读性:
- 通过使用有意义的枚举值和常量名,代码更加直观,读者能够轻松理解每个值的含义。
-
可维护性:
- 如果需要修改某个值,只需更改定义处即可,减少了出错的可能性。
-
类型安全:
- 枚举类型提供了一定程度的类型检查,减少了将无效值传递给函数的风险。
-
避免重复:
- 避免了在多个地方重复使用相同的魔法数,使代码更干净、更一致。
总结
魔法数是直接在代码中使用的具体数字常量,通常没有明显的解释或含义。通过使用枚举类型和常量,可以有效避免魔法数,提高代码的可读性、可维护性和类型安全性。这是一种良好的编程实践,能够使代码更加清晰、易懂和易于管理。
199. assert()的作用?
assert()
是一个调试程序时经常使用的宏,在程序运行时他计算括号内的表达式,如果表达式为False
(0),程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。
这个宏通常用来判断程序中是否出现了明显的非法数据,如果出现了终止程序以免导致更严重的后果,同时也便于查找错误。