1、关键字static的作用是什么?
-
在函数内部使用
static
修饰局部变量时,表示该变量在程序的整个生命周期内只会被初始化一次,并且在函数调用结束后不会被销毁,其值会一直保持。这种特性使得静态局部变量成为一种很有用的工具,可以在多次函数调用之间保持其值。 -
在全局变量前使用
static
关键字修饰,表示该全局变量的作用域被限制在当前文件内,其他文件无法访问该变量。通过这种方式可以实现全局变量的封装,避免被其他文件不小心修改。 -
在函数前使用
static
修饰时,表示该函数的作用域也被限制在当前文件内,其他文件无法调用该函数。这种方式可以实现函数的封装和隐藏,只允许当前文件内部调用。
2、.h头文件中的ifndef/define/endif 的作用?
用于防止头文件被重复包含,如果已经定义了该标识符,就不会再次包含头文件,从而避免重复 定义和编译错误。这样可以确保头文件只被包含一次,提高编译效率并避免潜在的错误。
3、全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
全局变量存储在静态数据区,而局部变量存储在栈区。
全局变量在程序运行期间始终存在,其内存空间在程序启动时分配,在程序结束时释放。局部变量则在函数被调用时创建,在函数执行结束时销毁,其内存空间随着函数的执行而动态分配与释放。
4、堆栈溢出一般是由什么原因导致的?
堆栈溢出通常是由递归调用或者过多的嵌套函数调用导致的。当一个函数被调用时,其参数和局部变量会被压入堆栈中,当函数执行完毕后,这些数据会被弹出堆栈。如果递归调用或者函数调用过多导致堆栈空间不足,就会发生堆栈溢出。另外,如果函数内部使用了大量的局部变量或者数组,也有可能导致堆栈溢出。
5、不能做switch()的参数类型?
switch()的参数类型不能是浮点型、双精度型、字符串型或者对象型。只能是整型或字符型。
6、局部变量能否和全局变量重名?
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
7、语句for( ;1 ;)有什么问题?它是什么意思?
和while(1)相同,无限循环。
8、do……while和while……do有什么区别?
前一个循环一遍再判断,后一个判断以后再循环。
9、程序的内存分配?
一个 C、C++程序编译时内存分为 5 大存储区:堆区、栈区、全局区、文字常量区、程序代码区。
1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。
5、程序代码区—存放函数体的二进制代码
10、堆和栈的区别?
1、分配内存的方式:
堆是由程序员分配和释放的,通过内存管理函数(如malloc、free)来操作堆内存。堆内存的生命周期由程序员控制,需要手动释放,否则可能导致内存泄漏。
栈是由编译器自动分配和释放的,编译器根据变量的作用域来管理栈内存。当一个函数被调用时,其局部变量存储在栈上,函数执行完成后,这些变量会自动释放。
2、存储方式:
堆是用于存储动态分配的内存,通常用来存储程序中需要长时间保存的大型数据结构,如数组、对象等。堆内存的访问速度较慢,因为需要通过指针来访问。
栈是用于存储局部变量和函数调用时的参数,栈内存的访问速度较快,因为数据的存取都在固定的位置进行。
3、内存管理:
堆内存需要手动分配和释放,程序员需要注意内存泄漏和内存溢出等问题。
栈内存由编译器自动管理,不需要程序员手动介入,因此更安全和方便。
11、C语言关键字
12、关键字const的作用?
Const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
const int *p: const修饰指向常量整数,指针指向的值不能被修改,但是指针可以指向其它的整数
int const *p: 修饰指针指向的内容,指向的值不能改变,指针可以指向其他的整数。
int * const p: 修饰指针p,p不能改变,指向的整数的值可以改变。
13、const与#define 相比,有何优点?
1、 const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
2、有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
14、typedef和define有什么区别?
1、用法不同:typedef 用来定义一种数据类型的别名,增强程序的可读性。define 主要用来定义常量,以及书写复杂使用频繁的宏。
2、执行时间不同:typedef 是编译过程的一部分,有类型检查的功能。define 是宏定义,是预编译的部分,其发生在编译之前,只是简单的进行字符串的替换,不进行类型的检查。
3、作用域不同:typedef 有作用域限定。define 不受作用域约束,只要是在 define 声明后的引用都是正确的。
14、extern有什么作用?
extern
标识的变量或者函数声明其定义在别的文件中,提示编译器遇到此变量和函数时在其它模块中寻找其定义。
15、数组与指针的区别?
-
内存分配:数组在内存中是一块连续的空间,其大小在编译时确定,因此数组的大小是固定的。而指针只是一个地址,它指向的数据可以是连续的,也可以是不连续的。
-
数据类型:数组的元素类型是固定的,而指针可以指向不同类型的数据。
-
表示形式:数组是一个特殊的数据类型,可以直接使用下标来访问元素。而指针是一个变量,存储的是地址,需要通过解引用操作*才能访问指向的数据。
-
传递方式:当数组作为函数参数传递时,实际上传递的是数组的首地址,即指针。因此在函数内部对数组的操作将改变原始数组的值。
16、c语言库函数中将一个字符转换成整型的函数?
用 法: int atoi(const char *str);
#include <stdio.h>
#include <stdlib.h>
int main()
{
char str[] = "1234";
int num = atoi(str);
printf("str:%s nun: %d\n", str,num);
return 0;
}
17、结构体和共用体的区别?
-
内存分配:
- 结构体中的数据成员占用独立的内存空间,结构体的大小等于所有成员占用内存空间之和。
- 共用体中的所有成员共享同一块内存空间,共用体的大小等于所有成员中占用内存空间最大的那个。
-
成员的访问:
- 对结构体成员的修改不会影响其他成员的值,每个成员都有独立的内存空间。
- 对共用体的赋值会影响其他成员的值,由于共用体的所有成员共享同一块内存,修改一个成员会影响其他成员的值。
-
用途:
- 结构体通常用于将多个不同类型的数据聚合在一起,以便组织相关的数据信息。
- 共用体一般用于节省内存空间,当几个成员中只有一个会被使用时,可以使用共用体来节省内存。
18、变量的声明和定义有什么区别?
变量的声明是指在程序中告诉编译器有一个变量存在,并且指定该变量的类型,但并没有为该变量分配内存空间。而变量的定义是指在程序中为变量分配了内存空间,同时也进行了初始化。
19、sizeof和strlen的区别?
-
sizeof:sizeof 是一个操作符,而不是一个函数。它用来获取一个数据类型或变量的大小,单位是字节。在使用时,sizeof 后面可以跟数据类型或变量名,用于获取它们所占用的内存空间大小。例如,sizeof(int) 会返回一个 int 类型的变量占用的内存空间大小,通常是 4 个字节。
-
strlen:strlen 是一个函数,用来获取字符串的长度,即字符串中字符的个数,不包括末尾的空字符 '\0'。在使用时,需要传入一个以空字符结尾的字符串作为参数,函数会返回这个字符串中字符的实际个数。例如,strlen("hello") 会返回 5,因为字符串 "hello" 中包含了五个字符。
20、strcpy、sprintf与memcpy的区别?
strcpy:是C语言中的字符串复制函数,用于将一个字符串复制到另一个字符串中。
使用strcpy时,必须确保目标字符串有足够的空间来存放源字符串的内容。如果源字符串超出目标字符串的长度,会导致内存溢出。
strcpy是以'\0'字符作为终止符,因此复制的内容会自动添加'\0'。
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20]; // 目标字符串需要足够大
// 使用 strcpy 函数复制字符串
strcpy(dest, src);
// 输出复制后的字符串
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
return 0;
}
运行结果:
sprintf:也是C语言中的字符串复制函数,功能类似于strcpy,但是可以将不同类型的数据格式化为字符串。
sprintf通常用于将整数、浮点数等转换为字符串,并将结果存储到目标字符串中。
和strcpy一样,使用sprintf时也要确保目标字符串有足够的空间。否则可能会导致内存溢出。
#include <stdio.h>
int main() {
char str[100];
int num = 10;
float fnum = 3.14;
// 使用 sprintf 将格式化的数据写入字符串
sprintf(str, "The number is %d and the float number is %.2f", num, fnum);
// 输出写入的字符串
printf("%s\n", str);
return 0;
}
运行结果:
memcpy:是C语言中的内存复制函数,用于将一个内存块的内容复制到另一个内存块中。
memcpy可以复制任意数据类型的内存块,而不仅仅是字符串。
使用memcpy时,需要指定要复制的源内存地址、目标内存地址以及要复制的字节数。
memcpy不会自动添加'\0'字符,因此在复制字符串时,需要手动添加终止符。
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20]; // 目标字符串需要足够大
// 使用 memcpy 函数复制字符串
memcpy(dest, src, strlen(src) + 1); // 需要复制的字节数为字符串长度加上结尾的空字符
// 输出复制后的字符串
printf("源字符串: %s\n", src);
printf("目标字符串: %s\n", dest);
return 0;
}
运行结果: