面经——C语言

数组初始化

int a[10] = {};//合法,但未初始化
int a[10] = {1,-1.0};//合法
 int a[10] = {1*10};//合法

(a+b)++不合法

c语言编译过程

预处理, 展开头文件/宏替换/去掉注释/条件编译 (test.i main .i)
编译, 检查语法,生成汇编 ( test.s main .s)
汇编, 汇编代码转换机器码 (test.o main.o)
链接 链接到一起生成可执行程序 (a.out)

https://blog.csdn.net/weixin_41143631/article/details/81221777

volatile关键字的作用

volatile指定的关键字可能被系统、硬件、进程/线程改变,强制编译器每次从内存中取得该变量的值,而不是从被优化后的寄存器中读取。
一般说来,volatile用在如下的几个地方:
1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;

结构体内存对齐

https://blog.csdn.net/renzemingcsdn/article/details/119191175

sizeof

运算符,不是函数,编译阶段确定
sizeof不能求得void类型的长度;
sizeof有三种语法形式,如下:
sizeof( object ); // sizeof( 对象 );sizeof( type_name ); // sizeof( 类型 ); sizeof object; // sizeof 对象;
数组的sizeof值等于数组所占用的内存字节数,如:

char a1[] = "abc";
int a2[3];
sizeof( a1 ); // 结果为4,字符 末尾还存在一个NULL终止符
sizeof( a2 ); // 结果为3*4=12(依赖于int)

指针变量的sizeof值与指针所指的对象没有任何关系,如

char* pc = "abc";
int* pi;
string* ps;
char** ppc = &pc;
void (*pf)();// 函数指针
sizeof( pc ); // 结果为4
sizeof( pi ); // 结果为4
sizeof( ps ); // 结果为4
sizeof( ppc ); // 结果为4
sizeof( pf );// 结果为4

sizeof的常量性:sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用。
数组退化为指针(在传递数组时,为避免拷贝太多数据而导致效率太低,只传递数组的首地址)的情况:

void fun(int a[10])
{
    int n = sizeof(a);   //结果为4,常见的陷阱
}

当sizeof表达式返回表达式的计算结果的类型大小,但不求值,求值过程无效;同样,对函数调用,求出返回类型的大小,补真正调用

 int i = 0,  j = 1;
cout<< sizeof(++i);//4,在编译过程,sizeof(++i)整体都变成4了,形成二进制文件后已经不存在i++了。
cout<<i;//0
cout<< sizeof(i+j);//4
 cout<< sizeof(j=i+j);4
 cout<<j;//1
 double d=1.0;
cout<< sizeof(j+d);//8
cout<< sizeof(j=j+d);//4

结构体共用体

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

回调函数

全局与局部重名

C语言里面可以,但是无法调用全局了

全局变量可不可以定义在可被多个.C文件包含的头文件中

两种情况,如果需要这些变量表名示同一个变量,是做不到的。语法上,可以加static,每个c文件中的该变量名表示的不同变量。

C/C++堆栈区别

(1)分配方式:堆由程序员分配和回收;栈由编译器分配和回收(2)碎片:堆经过多次new/delete或molloc/free后,会产生很多碎片。(3)生长方式:堆自下而上,栈自上而下。(4)效率:栈是由编译器直接生成指令,通常有专用的指令,由专用栈地址寄存器;堆区域分配需要便准库函数。

如何判断new和malloc是否成功

new是运算符失败会出发异常,malloc失败返回空指针。

手撕strcpy,memcpy,strcat,strcmp

https://blog.csdn.net/weixin_44580531/article/details/105471628

for循环及++技巧

以下程序的输出结果是

main()
{
	int x=10,y=10,i;
	for(i=0;x>8;y=++i)//for(单次表达式;条件;末尾表达式)
	{
		printf("%d,%d",x--,y);
	}
}

第一次for循环,y还没有赋值,故第一次输出:10,10,而后x减一,i先加一赋值给y,故=1。然后进入第二次循环,此时,x=9,y=1.

#pragma pack()

#pragma pack(2)
struct example
{
	char a;
	int b;
	char c;
};

sizeof(example)的结果等于8,两字节对齐。

* 与++

int a[]={1,2,3,4,5,6,7,8,9,10},*p=a;
则值为3的表达式是
A:p+=2,*(p++)//指针先赋值,指向第三个,后++,指向第四个,故返回3
B:p+=2,*++p //先++,指向第四个,后解引用,故返回4
C:p+=3,*p++ /*先加3 指向了4,*和++都是同级运算符,右结合。
但++要整个表达式运算完了才运算,先提取P指向对象的值,然后P再做++运算,指向下一个对象。*p++的意思就是先取出指针p指向的地址单元的数据,之后再将p这个地址加1。故返回4*/
D:p+=2,++*p//将第三个数加一返回4

简述memcpy和strcpy的区别?

(1)m可以拷贝任意数据类型,s只能拷贝字符串。(2)拷贝结束方式不同,m时指定大小,s是遇到‘\0’。

https://blog.csdn.net/renzemingcsdn/article/details/119206766

死循环

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

goto loop;

数据声明

声明一个整形 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)

typedef与#define

  • 执行时间不同:typedef是编译过程的一部分,#define是宏定义语句,预处理时完成。
  • typedef是给数据类型取别名,还可以定义数组指针结构体,#define是简单文本替换。
  • typedef:放在所有函数之外,它的作用域就是从它定义开始直到文件尾;放在某个函数内,定义域就是从定义开始直到该函数结尾。#define:不管是在某个函数内,还是在所有函数之外,作用域都是从定义开始直到整个文件结尾。
  • 二者修饰指针类型时,作用不同。
Typedef int* pint;
#define PINT int *  
Const pint p;//p不可更改,p指向的内容可以更改,相当于 int * const p;  
 Const PINT p;//p可以更改,p指向的内容不能更改,相当于 const int *p;或 int const *p;          

断言

在 C 语言中,断言被定义为宏的形式(assert(expression)),而不是函数,其原型定义在文件中。
其中,assert 将通过检查表达式 expression 的值来决定是否需要终止执行程序。也就是说,如果表达式 expression 的值为假(即为 0),那么它将首先向标准错误流 stderr 打印一条出错信息,然后再通过调用 abort 函数终止程序运行;否则,assert 无任何作用。
默认情况下,assert 宏只有在 Debug 版本(内部调试版本)中才能够起作用,而在 Release 版本(发行版本)中将被忽略。

malloc注意事项

malloc函数原型为 extern void *malloc(unsigned int num_bytes);使用的时候要进行类型转换;malloc函数使用后必须free;

C语言中"#“和”##"的用法

https://blog.csdn.net/baidu_33850454/article/details/79363033

你可能感兴趣的:(51job,c语言)