C语言常见面试题 笔试题 总结 makefile const和#define的区别 地址重叠 Memcpy sizeof和 strlen 大小端转换 堆和栈的区别 内存管理 static,extern

从.C文件到可执行文件具体流程

具体流程:
1、预处理:把源文件翻译成预处理文件
gcc -E code.c                  显示与处理结果
gcc -E code.c -o code.i         生成以.i 结尾的预处理的文件
2、编译:把预处理文件翻译成汇编文件
gcc -S code.i                  默认生成以.s 结尾的汇编文件
3、汇编:把汇编文件翻译成二进制的目标文件
gcc -c code.s                  默认生成以.o 结尾的目标文件
4、链接:把若干个目标文件合并成一个可执行文件
   gcc code.c a.o b.o c.o ...     默认生成一个a.out 的可执行文件

指针的作用

1、共享变量 2、提高传参效率 3、记录堆内存地址 4、与字符串结合

写指针函数

void *malloc(size_t size); 
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
… …

static,extern

static:
限制全局变量和函数的作用域。
改变局部变量、块变量的储存位置:由stack改为data或bss。
延长局部变量、块变量的生命周期:不会被销毁,初始化语句仅第一次有效。
	extern:
用于声明外部的变量,当a.c中有一个全局变量,b.c想要使用该变量就得用 extern 声明一下来使用。
extern声明只能让编译通过,如果链接时找不到,依然会报错。

有哪些类型限定符

	signed、unsigned、extern、auto、typedef、const、static、volatile、register

内存管理

一个C语言程序而言,内存空间主要由五个部分组成代码段(text)、数据段(data)、静态数据段(bss),
堆(heap)和栈(stack)组成,
其中代码段,数据段和静态数据段是编译的时候由编译器分配的,而堆和栈是程序运行的时候由系统分配的。

堆和栈的区别

堆是进程中的一个内存段,特点是足够大;栈是一种功能受限的表,只有一个出入端口,先进后出。
堆和栈的区别:
1、	栈中内存是由OS自动申请和自动释放; 堆中的内存需要程序员手动申请与释放。
2、	栈的空间大小并不大,一般最多为2M,超过之后会报Overflow错误。堆的空间非常大,最大可到达4G,可操作的空间非常大。
3、	栈由于其先进后出的特性,不会产生内存碎片; 堆中频繁调用malloc和free,会产生内存碎片。
4、	栈是由高地址向低地址扩展,自上而下; 堆是由低地址向高地址扩展,自下而上。
5、	栈有计算机专门分配的寄存器存放地址,有着很高的效率;堆需要通过库函数进行分配并在内存中搜寻足够大的空间,效率较低。
(堆都是动态分配的,没有静态分配。但是栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。
动态分配由malloc函数实现,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行和释放,无需程序员进行操作。)

全局变量,局部变量,函数传参 存在哪

被初始化过的全局变量存在data数据段,未被初始化过的全局变量存在bss静态数据段。
局部变量存储在stack栈中,但被初始化过的静态局部变量存储在data数据段,
未被初始化过的静态局部变量存储在bss静态数据段。
函数传参存储在栈中。

判断大小端(写出函数),为什么

地址由低位到高位编号,数据由高位到低位编号。
大端系统是数据的高字节存储在内存的低位地址;
小端系统是数据的高字节存储在内存的高位地址。

方法一:直接法

int main()
{
	int a = 0x12345678;
	char i = a;
	printf("%x",i);
	return 0;
}
定义一个十六进制int型数据0x12345678、一个char类型数据。
因为int型数据大小为4字节,而char类型数据为1个字节。
所以将int型数据赋值给char时会丢失3个字节数据,char类型中存储的是int类型中低地址的数据。
将char类型获取的数据输出后,如果输出的是12则为大端存储,如果输出的是78则为小端存储。

方法二:指针法

int main()
{
	int x = ox12345678;
	char *c = (char*)&x;
	if(c[0] == 0x12
		printf("big\n");
	else
		printf("little\n");
		
	return 0;
}
将0x12345678保存到int变量x中,在将其转换位char数组。如果数组第一个值是0x12那就是大端的,
而如果是0x78则说明是小端的了。

方法三:联合体法

union A
{
	char a;
	int b;
}A;
int main()
{
	A.b = 0x12345678;
	if(A.a == 0x12)
		printf("big\n");
	else
		printf("little\n");
		
	return 0;
}
在union中所有的数据成员共用一个空间,而且是从低位开始占用,所有的数据成员具有相同的起始地址。
在联合体中定义两个不同类型的变量,并定义第2个变量的地址为0x12345678。
如果第一个变量的地址为0x12则为大端,否则为小端。

0X12345678 大小端转换
移位法:

int main()
{
	int a = 0x12345678,b;
	b = ((a&0x000000ff)<<24) | ((a&0x0000ff00)<<8) | ((a&0x00ff0000)>>8) | ((a&0xff000000)>>24);
	printf("%x\n",b);

	return 0;
}

sizeof和 strlen 计算字符串,指针, 数组

sizeof对于字符串的处理与指针相同(4/8);而数组是根据数组定义时申请的内存空间大小(未定义申请大小时'\0'也算)。
strlen对字符串的处理和数组相同(以实际字符个数计算;'\0'不算);而对于未赋值的指针是一个不确定的值,
对于赋值的指针是按照实际的字符个数计算。

默写memcpy

#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
功能:从src位置中拷贝n个字节到dest中

Memcpy以及如果地址重叠了该如何拷贝

	void *memcpy(void *dest, const void *src, size_t n);
功能:从src位置中拷贝n个字节到dest中
地址重叠的话,使用与memmove:
mommove与memcpy相同,不同的是当to和from重叠,行数仍然可以工作。
#include <string.h>
void *memmove( void *to, const void *from, size_t count );

const和#define的区别

编译器处理不同:
宏定义是一个“编译时”概念。在预处理阶段展开(在编译时进行替换),不能对宏定义进行调试,生命周期结束于编译时期;
Const是在编译、运行时起作用。
存储方式不同:
宏定义直接替换,不会分配内存,存储于程序的代码段中;
Const常量需要进行内存分配,占用数据段空间。
类型和安全检查不同:
宏定义是字符替换,没有数据类型的区别,同时这种替换没有类型安全检查,可能产生错误;
Const定义是常量的声明,有类型区别,需要在编译阶段进行类型检查。
定义后能否取消:
宏定义可以通过#undef来使之前的宏定义失效;
Const常量定义后将在定义域内永久有效。

Makefile的内容,简单写一个makefile

Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
OBJ=main.o	phone.o	tools.o

all:$(OBJ)
	gcc	-o    phone_book    $(OBJ)

main.o:main.c	tools.h    phone.h
	gcc	-c    main.c

tools.o:tools.c    tools.h
	gcc	-c    tools.c

phone.o:phone.c    phone.h    tooh.h
	gcc	-c    phone.c

clean:
	rm -rf $(OBJ)	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值