2023最新C语言经典面试题汇总

写出Bool、int、指针变量、float与“零值”比较的if语句

Bool型:

if(flag)、if(!flag)

int型:

if(flag == 0)、if( flag!= 0)

指针变量:

if(p == NULL)、if( p!= NULL)

float型:

const float EPSINON = 0.0001; if( (x >= -EPSINON) && (x <= EPSINON));

设置地址未为0x67a9的整型变量的值为0xaa66

int *prt;
ptr = (int *)0x67a9;
*ptr = 0xaa66;
*(int *)0x67a9 = 0xaa66;

要对绝对地址赋值,我们可以用(unsigned int*)0x10000=1234,那么要想程序跳转到绝对地址是0x10000去执行,应该怎么做?

先强制转换成函数指针:(void(*)())0x10000;

再调用它:*( ( void(*)( ) )0x10000 )();

描述一下gcc的编译过程

gcc编译过程分为4个阶段:预处理、编译、汇编、链接

预处理:进行头文件、宏定义的替换,条件编译,删除注释,还有语义和词义的分析

编译:将预处理后的文件编译成汇编文件

汇编:将汇编文件转换二进制文件

链接:将二进制文件链接成可执行文件

#include< >和#include" "的区别

#include< >是到系统指定目录下寻找文件;

#include" "是先到用户指定的目录下寻找文件,找不到就到系统指定目录下寻找

头文件中的ifndef/define/endif 干什么用

防止头文件被重复引用。

有符号与无符号的区别

有符号的数据,最高位为符号位,0表示正数,1表示负数;

无符号的数据,最高位不是符号位,只是数据的一部分。

sizeof与strlen的区别

sizeof是操作符,参数可以是数据类型,也可以是变量,在编译时就已经计算出来sizeof的结果,计算的是数据类型占内存的大小;

strlen是库函数,参数只能是以‘\0’结尾的字符串,需要在运行时才能计算出来,计算的是字符串的长度;

嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环

while(1)
{}
for(;;)
{}
loop: ···
goto loop;

宏定义

写一个标准宏MIN

#define MIN(x,y) ( (x)<=(y)? (x):(y) )

用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define SEC_YEAR (365 * 24 * 60 * 60)UL

用宏定义写出swap(x,y),即交换两数

#define swap(x,y) x=x+y;y=x-y;x=x-y;

已知一个数组table ,用一个宏定义,求出数据的

#define LENGIH sizeof(table)/sizeof(table[0])

关键字

关键字static的作用是什么

  1. 修饰局部变量时,变量只执行一次,存在于静态存储区,不初始化内容为0,只在当前语句块有效,程序结束后才释放。

  2. 修饰全局变量时,变量存在于静态存储区,不初始化内容为0,只在当前文件有效,程序结束后才释放。

  3. 修饰函数时,该函数只能在当前文件中使用。

static函数与普通函数的区别与好处

static修饰的函数只能在当前文件使用;

普通函数可以被外部文件用extern调用;

用static修饰函数的好处是:

  1. 其他文件可以定义相同名字的函数;

  2. 该函数不能被其他文件调用;

static修饰变量的作用与好处

修饰局部变量:存在于静态存储区,补初始化内容为0,作用域在当前函数/语句块;

修饰全局变量:存在于静态存储区,不初始化内容为0,作作用域只在当前文件;

用static修饰变量的好处是:

  1. 其他文件可以定义相同名字的变量;

  2. 该变量不能被其他文件调用;

关键字volatile有什么含意?并给出三个不用的例子

volatile指的是易变的。 用以告诉编译器被volatile修饰的变量随时可能被改变。

以下场合需要用到volatile修饰:

  1. 中断服务程序中修改的供其他程序检测的变量;

  2. 多任务环境下共享的标志;

  3. 存储器映射的硬件寄存器;

关键字 _interrupt

_interrupt是用来定义中断服务子程序ISR的,它有以下几个特点:

  1. ISR不能返回一个值;

  2. ISR不能传递参数;

  3. 最好不要做浮点运算;

  4. 最好不要加打印;

关键字const有什么含义

const代表着只读,让编译器去保护那些不希望被改变的参数。

  1. 定义变量,变量的值不能被改变

  2. 定义指针,指针的值不能被改变

  3. 定义类的成员函数,成员函数不能改变类的变量

以下代码声明的含义是什么

  1. const int a;

  2. int const a;

  3. const int *a;

  4. int* const a;

  5. const int* const a;

  1. a是一个常数整数

  2. a是一个常数整数

  3. a是一个指向常数整数的指针,指针的值不可修改,但是指针可以修改

  4. a是一个指向整数的常量指针,整数的值可以修改,但是指针不可修改

  5. a是一个指向const整数的const指针,整数和指针的值都不可以修改

c和c++ 中的struct有什么不同

  1. C中的struct不能有成员函数,而C++的struct可以。

  2. C中struct的默认权限是public,而C++的struct是private。

内存

内存最小存储单元以及内存最小计量单元是什么

内存最小存储单元是Bit(二进制位)

内存最小计量单元是Byte(字节)

描述一下内存分区

程序在运行前:代码区、BSS段(为未初始化数据区)、data段(初始化数据区);

程序在运行后:堆区、栈区、全局区(静态区)、代码区、文字常量区。

stack栈与heap堆的区别

stack栈由系统自动分配,其地址和容量是系统定的,是一块连续的内存(Window下是2M);

heap堆是用户自己用malloc申请的,char p = (char)malloc(),它是不连续的。

malloc()与new()的区别

  • malloc

  1. 是在堆中申请内存,申请需要指定大小

  2. 返回void*类型,需使用强制转换

  3. 失败返回NULL

  • new

  1. 是在自由存储区申请内存,无需指定大小

  2. 返回对象类型指针,无需转换,安全

  3. 失败返回mac_alloc异常

内存溢出一般是由什么导致的

  1. 动态申请的空间没有回收

  2. 数组越界访问

变量

变量的命名规则

变量名由字母、数字、下划线组成,但是不能以下划线开头。

变量的声明和定义有什么区别

变量的定义需要定义存储空间;

变量的声明不需要建立存储空间。

描述普通局部变量、普通全局变量、静态局部变量、静态全局变量的区别

普通局部变量:存在于栈区,不初始化内容随机,只作用于当前语句块,语句块结束变量空间释放。

普通全局变量:存在于全局区,不初始化内容为0,作用于当前文件,也能被其他文件用extern调用,进程结束变量空间才被释放;

静态局部变量:存在于静态存储区,不初始化内容为0,作用于复合语句,进程结束变量空间才被释放;

静态全局变量:存在于静态存储区,不初始化内容为0,只作用于当前文件,进程结束变量空间才被释放。

用变量a进行定义

  • 一个整型数

int a

  • 一个指向整型数的指针

int *a

  • 一个指向指针的指针,它指向的指针是指向一个整型数

int **a

  • 一个有10个整型数的数组

int a[10]

  • 一个有10指针的数组,该指针是指向一个整型数

int *a[10]

  • 一个指向有10个整型数数组的指针

int (*a)[10]

  • 一个指向函数的指针,该函数有一个整型数参数并返回一个整型数

int (*a)(int)

  • 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型数参数并返回一个整型

int (*a[10])(int)

如何定义一个已经引用过的全局变量

  1. 头文件定义

  2. extern调用

数组

数组的特点

  • 所有成员都是相同的数据类型

  • 所有成员再内存中地址是连续的

数组的分类

数组的分类有:静态数组、动态数组。

静态数组:在程序运行前就确定了大小,且运行中大小不能更改。

动态数组:主要是在堆中申请的空间,大小在运行中确定,且可以更改。

一维数组在不初始化、部分初始化、完全初始化的区别

不初始化:如果是局部数组,内容随机;如果是全局数组,内容为0;

部分初始化:未初始化的部分自动补0;

完全初始化:数组大小由初始化的个数确定。

数组作为类型、作为地址、取地址的区别

数组作为类型:代表整个数组的大小;

数组作为地址:代表数组首元素地址;

数组取地址:代表数组首地址。

二维数组在物理和逻辑上的区别

在物理上是一维的,在逻辑上是二维的。

函数

函数的定义与函数的声明有何区别

函数的定义:指的是对函数功能的确立,包括函数类型、函数名、形参、函数体。

函数的声明:告诉编译器这个函数的类型、名字、形参。

宏函数的概念以及作用

把一些短而小、使用频繁的函数写成宏函数;

由于宏函数没有普通函数的压栈、跳转、返回等开销,可以提高代码效率。

指针

描述一下32位或64位平台下指针的大小

32位平台:任意类型的指针大小为4字节;

64位平台:任意类型的指针大小为8字节;

指针数组的概念

本质是一个数组,数组中的每一个元素都是一个指针。

使用realloc给已分配的堆区空间追加空间时需要注意什么

用指针变量保存realloc的返回值。

什么情况下会出现野指针

  1. 指针未初始化

  2. 指针释放后未置空

  3. 指针操作超出其作用域

引用与指针的区别

  1. 引用必须初始化,指针不必初始化

  2. 引用初始化用不能被改变,指针可改变

  3. 引用不可指向空值,指针可指向空值

指针作为函数参数的输入特性和输出特性

输入特性:主函数分配空间,被调函数使用空间;

输出特性:被调函数分配空间,主函数使用空间。

(void )ptr 和((void**))ptr 的结果是否相同?其中ptr为同一个指针

一样的。

结构体

结构体和共用体的区别是啥

结构体的成员拥有独立的空间;

共用体的成员共用一块空间,并且成员能访问的口昂见大小由成员自身类型决定。

如何理解结构体的浅拷贝和深拷贝

当结构体中出现指针成员的时候容易出现浅拷贝和深拷贝的问题。

浅拷贝:两个结构体的指针成员指向同一块区域空间,结构体释放时这块空间会被多次释放;

深拷贝:两个结构体指针成员指向不空的区域空间,只是内容拷贝一份,结构体释放时不会出现同一个空间被释放多次的情况。

文件

文件缓冲的几个刷新方式

  • 行缓冲

  • 满缓冲

  • 强制缓冲

  • 关闭缓冲

谈谈文件的分类

文件分为二进制文件和文本文件。

二进制文件基于值编码,需要根据具体的应用才能知道某个值的意思;

文本文件基于字符编码,一个字节一个意思,可以通过记事本打开。

进程

进程通信(IPC)的方式

  1. 管道(pipe/fifo)

  2. 消息队列

  3. 共享内存

  4. 套接字socket

  5. 信号

  6. 信号量

字节对齐

代码

*ptr++ 、++ptr和++ptr相同吗?

ptr++等价于(ptr++);

++ptr等价于++(ptr);

++ptr等价于(++ptr);

请问以下代码有什么问题

int main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}

没有给str分配空间,将一个字符串支复制给一个字符变量指针将会发生异常,因为越界读写导致系统崩溃。 正确修正方法:

char a[10]; char *str = a;

以下代码有什么出错的地方

char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);

编译正确,运行错错误,“AAA”是字符串常量,s[0]试图修改字符串常量的指值,字符串常量不能修改。

以下代码有什么出错的地方

wap( int* p1,int* p2 )
{
int * p;  //(int)malloc(4); is ok
*p = *p1;
*p1 = *p2;
*p2 = *p;
}

没有给指针p分配空间,为空指针,无法存储指针p1的值。

编写memcpy函数

void* memcpy(void* dest,const void* src,int size)
{
  if(dest == NULL || src == NULL)
      return dest;
  while(size--)
  {
      *(char*)dest = *(char*)src;
      dest = dest+1;
      src = src+1; 
  }
  retern dest;
}

编写strcpy函数并解释为什么要返回char型

char* strcpy(char* strDest,const char* strsSrc)
{
  if(strDest == NULL || strSrc == NULL)
    return NULL;
    
    char*p = strDest;
    
    while(*strsSrc != '\0')
    {
        *p++ = *strsSrc++;
    }
    *p = *strSrc;
    return strdDest;
}

返回char类型是为了增加灵活性,比如链式操作,例如:

int length = strlen( strcpy(str,"Hello World") );

小结

我记得曾经有人说过,思想和行动的区别在于:

想谈恋爱却高呼自由可贵,想进大厂却不想工作,想当大牛却不想学习,每个人都知道明天必须披荆斩棘的活下去,却依旧浑浑噩噩的度过今天。

不用去怀疑自己的能力,你只需要一份靠谱的学习资料,一个学习的deadline以及一个没学完就打爆你狗头的人,很快你就会被自己的才华和能力所惊艳。

我收集了一些linux的资料,算法小抄和计算机基础的资料。

以下资料仅供个人学习使用,欢迎大家一起学习探讨。

linux保姆级教程完整版文档资料

希望以上内容能帮助到你,祝各位生活愉快。

你可能感兴趣的:(C/C++,c语言,开发语言,面试题,C语言笔试题)