C语言面试知识点

c语言常见知识点

1. c语音中内存是如何分布的?

c语言中,内存分为5个区, 分贝是栈区、堆区、全局/静态存储区、常量存储区、代码区
在这里插入图片描述
在这里插入图片描述

栈区:

  1. 栈区由编译器自动分配释放,由操作系统自动管理。
  2. 栈区上的内容只在函数范围内存在,当函数运行结束,这些内容会自动被销毁。
  3. 栈区是先进后出原则。

存放内容:

  1. 临时创建的局部变量,和const定义的局部变量存放在栈区
  2. 函数调用和返回时,其入口参数和返回值存放在栈区

堆区:

  1. 堆区由程序员分配内存和释放
  2. 堆区按内存地址由低地址到高地址增长。malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。

全局(静态)区:

  1. 编译器编译时即分配内存,全局变量和静态变量的存储是放在一块的。
  2. C语言中,已初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
    全局区有 .bss段 和 .data段组成,可读可写。

常量区

  1. 字符串、数字等常量存放在常量区
  2. const 修饰的全局变量存放在常量区
  3. 程序运行期间,常量区的内容不可以被修改。

代码区:

  1. 程序执行代码存放在代码区, 其值不能修改
  2. 字符串常量和define定义的常量也有可能存放在代码区

2.c语言内存中堆区和栈区的区别?

1.分配方式:
栈区: 栈区是由编译器自动分配和释放的,用于存储局部变量和函数调用信息。栈的分配和释放是由编译器隐式完成的,遵循后进先出(LIFO)的原则。
堆区: 堆区是由程序员手动管理的,用于存储动态分配的内存。在堆上分配内存需要使用诸如 malloc、calloc 或 new 等函数,而释放内存则需要使用相应的释放函数,例如 free 或 delete。
2.生命周期:
栈区: 变量在栈上的生命周期与其所在的函数调用相关,当函数返回时,栈上的局部变量会被自动销毁。
堆区: 堆上的内存的生命周期由程序员显式管理,可以在需要时分配,直到显式释放。
3.大小限制:
栈区: 栈的大小通常受到限制,因为它由系统分配,并在函数调用时自动管理。栈上的变量通常较小,并受限于栈的大小。
堆区: 堆的大小通常受到系统或编译器的限制,但相对于栈来说,它可以分配更大的内存块。
4.分配效率:
栈区: 栈的分配和释放是非常高效的,因为只需要移动栈指针即可完成。
堆区: 堆的分配和释放可能相对较慢,因为需要搜索合适的内存块并进行管理。
总体来说,栈区用于存储局部变量和函数调用信息,其管理由编译器自动完成; 而堆区用于存储动态分配的内存,其管理由程序员手动进行。正确的使用和管理堆内存对于避免内存泄漏和提高程序的灵活性至关重要。

3. c语言中标识符(变量)的命名规则

  1. 不能以数字开头
  2. 可以由数字,字母,下划线组成
  3. 不能是关键字
  4. 区分大小写

4. 在c语言中定义和声明的区别

声明:
声明不会给变量分配内存空间
定义:
定义会给变量分配空间
程序运行时为其变量或函数开辟内存空间,定义只能定义一次

5. 计算机中内存的最小存储单位和内存的最小计量单位分别是什么?

内存的最小存储单位是比特(bit),而最小计量单位是字节(byte)
一字节等于8比特

6. 描述一下c语言的编译过程并简述每个过程做了什么

c语言的编译过程分为4个阶段: 预处理,编译,汇编,链接
1. 预处理:头文件包括,宏替换,条件编译,删除注释
2. 编译: 主要进行语法,语义分析等,检查无误后将预处理好的文件编译成汇编文件。
3. 汇编: 将汇编文件转换成二进制文件
4. 链接: 将项目中的各个二进制文件和所需要的库和启动代码链接成可执行文件。

7. #include<> 与#include “” 的区别

  1. #include <> 到系统指定目录寻找头文件
  2. #incude " " 先在项目目录寻找头文件,如果没有找到再到系统指定目录寻找头文件

8. 指针和指针变量是一个意思? 他们有什么区别?

指针和指针变量是不同的, 指针就是地址值,是一个数据,而指针变量是c语言中的变量,要在待定区域开辟空间,用来保存地址数据,还可以被取地址
区别:

  1. 指针的本质是地址
  2. 指针变量的本质是变量,是用来存放地址的, 也就是说指针变量是用来存放数据的

9.野指针产生的原因?如何避免产生野指针?

野指针概念:
野指针就是指针指向的位置是不可知的
野指针产生的原因:

  1. 指针未初始化就使用
  2. 指针越界访问
  3. 指针指向了一段已经释放的空间(指向了垃圾内存空间)

避免野指针的方法:

  1. 指针初始化
  2. 避免指针越界
  3. 指针指向空间释放即置为NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

10.一个指针变量占几个字节

一个指针在32位的计算机上,占4个字节;
一个指针在64位的计算机上,占8个字节。

11.递归函数定义没有问题, 递归深层次易引发什么问题?

1.最主要的问题是栈溢出(Stack Overflow)。这是由于每次函数调用都会在程序的调用栈上分配一些空间,而递归调用的深度过大会导致栈空间耗尽。
2.执行效率降低。 递归调用相对于迭代(循环)调用通常会涉及更多的函数调用开销和额外的栈空间分配,可能会导致性能下降。

12. 循环控制条件关键字goto的使用场景有哪些?为什么goto的使用场景受到限制?

  1. 常用来跳出死循环
  2. 打印错误
    因为goto会破坏程序的栈逻辑,同时使用 goto 可能导致代码的结构变得复杂,使得程序更难以理解和维护

13. 什么是字节对齐

各种数据类型按照一定的规则在空间上进行排列,而不是顺序地一个接一个地存放,这就是字节对齐。

14. 局部变量和全局变量可以重名吗

C语言中局部变量可以与全局变量同名,局部变量会屏蔽全局变量,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量

15. const 关键字使用有哪些?

const 用于声明常量和指定变量为只读,用途如下:

  1. 声明常量
  2. 指定只读变量
  3. 指定只读指针
  4. 指定自读函数参数

16. sizeof() 与strlen()的区别

  1. sizeof() 是运算符, 用于获取数据类型或对象在内存中占用的字节数,sizeof接受类型或表达式作为参数,返回指定类型或对象的字节大小。
  2. strlen() 是一个函数, 用于计算字符串的长度, 即字符串中的字符个数, 不包括结尾的NULL字符(‘\0’),strlen 接受一个以 null 结尾的字符串作为参数,返回字符串的长度。
#include <stdio.h>
#incude <string.h>
int main(int argc, char **argv)
{
	char arr[] = "hello";
	printf("sizeof=%ld\n",sizeof(arr));
	printf("strlen=%ld\n",strlen(arr));
	return 0;
}

在这里插入图片描述

17. 内存泄漏和内存溢出分别是什么?

1. 内存泄漏
内存泄漏指的是程序在动态分配内存后, 没有正确释放这部分内存,导致程序无法再次使用这块内存,从而造成了内存资源的浪费。
2. 内存溢出:
内存溢出是指程序试图向一个已经分配的内存区域写入超过该区域大小的数据,导致数据越过了内存边界,覆盖了其他内存区域的数据

18. 定义一个指针赋值字符串与定义一个数组赋值字符串有什么区别?

1. 指针赋值字符串:
char *str = “hello word”;
使用指针时, 实际是将指针指向字符串常量的首地址,字符串常量存储在只读的数据段,不能通过指针修改字符串的内容
2. 数组赋值字符串:
char str[] = “hello word”;
使用字符串数组,会在栈上分配足够的空间来存储字符串的内容,并在数组的末尾添加NULL字符(‘\0’), 可以通过字符串的读写操作,因为它在栈上分配了一块可读写的内存空间
总体而言,使用指针赋值字符串时,指针指向字符串常量,不能修改字符串内容。而使用字符数组赋值字符串时,数组在栈上分配一块内存,可以进行读写操作。

19. static 关键字的作用?

三种情况: 修饰局部变量,修饰全局变量,修饰函数
1. static 修饰局部变量:
static 修饰的局部变量只能在函数体内使用,并且静态局部变量的值不会因为函数调用的结束而清除,当函数再次调用时,该变量的值是上次调用结束后的值。静态局部变量被存储在静态存储区(局部变量存储在栈区)。并且静态局部变量会被自动初始化为0
2. static修饰全局变量:
static修饰的全局变量成为静态全局变量。该变量只能在被当前文件的所有函数访问,不可以被其他文件内的函数访问。
3. static修饰函数:
static修饰的函数成为静态函数。同样静态函数只能在当前文件中被调用,不能被其他文件调用。将函数限制在当前源文件中,防止在其他源文件中被访问。

20. 数组与链表的区别?

1. 内存分配方式
数组在内存中是一块连续的存储空间,元素之间的地址是相邻的
链表的节点在内存中可以是分散的,每个节点包含一个数组元素和指向下一个节点的指针
2. 大小和扩展性:
数组的大小是固定的,一旦创建就不能轻易改变。如果需要更大的空间,可能需要重新分配内存,并将数据复制到新的内存位置。
链表的大小可以动态增长或缩小,因为它不需要一块连续的内存空间。
总的来说,数组的数据是连续存储的,大小固定,链表的数据可以随机存储,大小可以动态改变。

21.指针和引用的区别(c和c++中的问题)?

指针: 使用 * 操作符来声明指针和访问指针指向的值,同时使用&操作符获取变量的地址。

int x = 10;
int *ptr = &x;
int value = *ptr;

**引用:**使用 & 操作符来声明引用, 而引用的时候不需要 * 操作符

int x = 10;
int &ref = x;
int value = ref;

2.空指针和空引用:
指针: 指针可以是空指针,即指向空地址(null)
引用: 引用必须在声明时初始化,并且不能引用空值,引用在声明后始终引用同一个对象。
3. 空间占用
指针: 指针通常占用一定的空间,存储目标对象的地址。
引用: 引用在内部不占用额外的空间,它被视为原对象的别名。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值