经典C面试真题精讲

第一章 灵魂--指针

 

101. p++

请分析下述代码的输出结果

int main()
{
    char* p1 = "China";
    char* p2, * p3;
    
    p2 = (char*)malloc(20);
    
    memset(p2, 0, 20);
    
    while(*p2++ = *p1++);
    
    printf("%s\n", p2);
    
    return 0;
}

答案:输出为空。

 

102. 打印内存地址

请问在printf打印函数中一般用什么形式打印变量内存地址?

答案:最常用的打印地址方式是%p和0x%x两种。

 

103. sprintf()与snprintf()

 请问printf()、sprintf()和snprintf()函数有什么区别?

答案:三个函数原型如下,

int printf(const char *format,...);

int sprintf( char *buffer, const char *format, [ argument] … );

int snprintf(char *str, size_t size, const char *format, ...);

 

104. 指针常量与常量指针

请问下述两段代码中的p有什么区别?

代码1:

int i = 10;
int* const p = &i;

代码2:

int i = 10;
const int* p = &i;

答案:代码1表示指针p是常量,其值不可改变;代码2表示p指针指向的数据不可改变。(左数右指)

 

105. 字符与字符串

已知

char c = 'a';
char* cp = "a";

请问c与cp的区别?

答案:c是字符变量,cp是字符串指针变量

 

106. 指针变量与普通变量

 请问下述代码输出结果是()?

int main()
{
    int x, *p;
    
    p = &x;
    *p = 0;
    
    printf("x: %d\n", x);
    printf("*p: %d\n", *p);
    
    *p += 1;
    
    printf("x: %d\n", x);
    
    (*p)++;
    
    printf("x: %d\n", x);
    
    return 0;
}

答案:0 0 1 2

 

107. 指针运算

 请问下述代码的输出结果是()?

int main()
{
    int* ip1, * ip2, ivalue;
    char* cp1, * cp2, cvalue;
    
    ip1 = (int*)0x500;
    ip2 = (int*)0x518;
    
    ivalue = ip2 - ip1;
    
    cp1 = (char*)0x500;
    cp2 = (char*)0x518;
    
    cvalue = cp2 - cp1;
    
    printf("%d, %d\n", ivalue, cvalue);
    
    return 0;
}

答案:6, 24

,

108. “%-10.5s”

分析下属程序的输出结果()

int main()
{
    char* str = "Hello, Beijing";
    
    printf("%s\n", str);
    printf("%10.5s\n", str);
    printf("%-10.5s\n", str);
    
    return 0;
}

答案:“%10.5s”指定的字符串输出格式是每行固定占10个字符位置,并且右对齐显示5个字符。

“%-10.5s”指定的字符串输出格式是每行固定占10个字符位置,并且左对齐显示5个字符。

 

109. 字符串复制

编写一个函数,实现类似strcpy的字符串复制函数。原型定义为char* mystrcpy(char* dest, char* src)。功能是把src所指向的字符串复制到dest所指的数组中,返回dest指针。

提示:src和dest所指内存区域有可能重叠

 

110. 统计字符个数

输入一段字符串,要求统计其中的小写字母出现的次数,并按照出现次数的多少依次输出。当出现相同次数的字母时,按照字母的先后顺序一次输出。假如输入字符串是“mike.lee@ChianBeijing”,则输出为

aghjklm : 1
n : 2
ei : 4

假设函数原型定义为void calcCharCount(char* s),其中参数s为要统计的字符串的指针。

 

111. 一维数组与指针

已知char* p = "abcd"; char c[] = "abcd"; 请问p++与c++是否相同?为什么?

答案:c++是非法的,数组名相当于一个指针常量。

 

112. 数组中的strlen与sizeof区别

下述代码输出结果是()

int main()
{
    char* p = "abcde\0f";
    char a[] = "abcde\0f";
    
    printf("%2d\n", strlen(p));
    printf("%2d\n", sizeof(p));
    printf("%2d\n", strlen(a));
    printf("%2d\n", sizeof(a));
    
    return 0;
}

答案:5 4 5 8

 

113. 多维数组

请分析下述代码的输出结果。

int main()
{
    int a[2][3][4] = {
        101, 102, 103, 104,
        111, 112, 113, 114,
        121, 122, 123, 124,
        
        201, 202, 203, 204,
        211, 212, 213, 214,
        221, 222, 223, 224,
    };
    
    printf("%5d\n", **(a[0] + 2));
    printf("%4d\n", sizeof(a));
    
    
    return 0;
}

答案:121 24

 

114. 数组作为参数传递给函数

已知如下代码,请分析输出结果。

void fsizeof(int a[][3])
{
    printf("%d\n", sizeof(a));
}

int main()
{
    int a[2][3] = {
        {101, 102, 103},
        {201, 202, 203}
    };
    
    fsizeof(a);
    
    return 0;
}

答案:4

 

115. char(*(*x())[5]())与typedef

Given char(*(*x())[5])(); Please describe the meaning of x

 

116. 编程求较大数的阶乘

计算整数为N的阶乘,要求计算的结果最长可达50位的整数(此处位的单位是十进制而不是二进制)。

提示:一般32位系统中存储数据最大的基本数据类型double最长存储的十进制数据为20位

 

117. 字符旋转

编写一段程序,要求输入连个整数(>=1)M、N,生产一个M*N的矩阵,矩阵中元素取值为A至Z的26个字母红的任意一个,A在左上角,其余各数按顺时针方向旋转前进,依次递增放置,当超过26时又从A开始填充。例如,当输入M、N分别为10、13时,输出结果如图所示

 

118. __attribute__((__packed__))含义

已知3个结构体的定义如下,请问sizeof(A),sizeof(B),sizeof(C)的值各为();

typedef struct engineer_p{
    char Name[10];
    int Id;
    char Department[10];
}__attribute__((__packed__)) A;

typedef struct engineer1{
    char Name[10];
    int Id;
    char Department[10];
} B;

typedef struct engineer2{
    int Id;
    char Name[10];
    char Department[10];
} C;

答案:24、28、24

 

119. union与struct类型区别

 请分析下述代码的输出结果

union a
{
    char name[5];
    int no;
};

struct b
{
    char name[5];
    int no;
};

int main()
{
    printf("%d\n", sizeof(union a));
    printf("%d\n", sizeof(struct b));
    
    
    return 0;
}

答案:8 12

 

120. Little-endian与Big-endian

Please write a C application to check the CPU work on Little-endian mode or Big-endian mode.

 

 

第二章 数据存储--内存

 

201. char* a[3][4]占内存大小。

请分析下述代码的输出。

#include 

int main()
{
    char* a[3][4];
    printf("%d\n", sizeof(a));
    return 0;
}

答案:48

 

202. int* p[M]与int(*p)[M]

请问int* p[M]与int(*p)[M]有什么区别?

答案:int* p[M]是一个指针数组,int(*p)[M]是一个数组指针。

 

203. 数组元素指针与数组元素大小的计算

以下代码的输出结果是(假设运行在32位系统上)()。

struct st_t
{
    int status;
    short* pdata;
    char errstr[32];
};

int main()
{
    struct st_t st[16];
    char* p = (char*)(st[2].errstr + 32);
    
    printf("%d\n", (p - (char*)st));
    
    return 0;
}

答案:120

 

204. #define与typedef区别

What is the type of the variable b in the following declarations?

#define FLOATPTR float*
FLOATPTR a, b;

答案:float

 

205. sizeof(p)

对于以下几种不同类型的指针变量p,请问sizeof(p)各是多少?

char p[] = "hello!";
char* p = "hello!";
void* p = malloc(100);
void Func(char p[100]);
struct student{
    char name[10];
    int age;
    int id;
} *p;

答案:7 4 4 4 4

 

206. 关键字“static”修饰变量与函数

关键字static修饰变量与函数的主要作用有哪些?

 答案:

① 缩小作用域

② 是变量内容寿命变长

③ 修饰变量默认初始化为0

 

207. char不等于unsigned char

对于unsigned char a = -1; signed char a = -1; char a = -1;,用printf("%d\n", a)打印的结果是否相同?为什么?

 

208. unsigned类型值与0的关系

请问下述代码有什么问题?

int fd = -1;
unsigned int tw = 0, rn = 0;

fd = open("test.in", O_CREAT | O_RDWR, 666);
assert(fd >= 0);

for(tw = len; tw >= 0; tew-= rn, src += rn)
{
    if((rn = write(fd, src, tw)) < 0)
        return -1;
}

答案:变量tw类型为unsigned int,不等式tw >= 0恒成立,所以for语句会陷入死循环。

 

209. 不同数据类型的赋值

请问下述代码有什么问题?

int main()
{
    short int a = 0x1234;
    unsigned int* c;
    
    c = (int*)&a;
    printf("c = 0x%.8x\n", *c);
    
    return 0;
}

答案:使用了非法内存。

 

210. 验证C语言内存分配

编写一段程序,用验证局部变量(包含static类型)、全局变量(包含static类型)、动态申请的内存变量在内存中的地址及默认初始值。

 

211.返回栈地址

请问下述代码有什么问题?

char* func()
{
    char a[5] = "abcd";
    char b[5];
    
    strcpy(b, a);
    
    return b;
}

答案:栈内地址不能传递到函数之外,栈内存不需要手动释放。

 

212. 未初始化与内存访问越界

请分析下述代码潜在的问题

int main()
{
    char a[20] = "I'am an engineer";
    char* p;
    
    p = (char*)malloc(30);
    if(p == NULL)
        return -1;
    
    memcpy(p, a, 25);
    
    printf("%s\n", p);
    
    free(p);
    
    return 0;
}

答案:内存访问越界。

 

213. 使用已经释放的内存

请分析下述代码潜在的问题

free(hotbmp->pHotBitmapCacheMemory);
free(hotbmp);
hotbmp->pHotBitmapCacheMemory = NULL;
hotbmp->HotBitmapCacheLength = 0;
hotbmp = NULL;

答案:使用已经free掉的指针。

 

214. 数组越界

请分析下述代码潜在的问题

while(m > 0)
{
    unsigned char c1, c2;
    
    c1 = buf[offset++] - 'A';
    c2 = buf[offset++] - 'A';
    
    if((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name) - 1))
        break;
    
    name->name[n++] = (c1 << 4) | c2;
    m -= 2;
    
}

name->name[n] = 0;

答案:

 

215. 内存泄漏之内存释放顺序

请问下述代码的释放内存是否正确?如果不正确,请说出理由。

 

216. 内存泄露之重新赋值

 请找出下述代码中引起内存泄漏的一行代码。

 

217. 内存泄漏之谨慎使用函数返回值

请问下述代码是否会引起内存泄漏?如果是,请分析原因,并给出一个解决办法。

 

218. 内存泄漏之退出函数路径

请问下述代码是否会引起内存泄漏?

 

219. 时间GeneralizedTime编码格式

请写一个函数实现时间格式转换的功能。

 

220. 浮点数的存储格式

对于单精度浮点数-21.375在内存中存放的实际数据是什么?请写一段程序,当输入一个单精度浮点数时,打印出该浮点数在内存中实际存放的数。

 

221. 实现小应用--万年历

对于日期的查询是人们日常生活中很重要的一个需求,

 

 

第三章 程序的思想--算法

 

301. 栈--迷宫问题

 以一个M*N的数组表示迷宫,数组元素的内容0和1分别表示迷宫中的通路和障碍。设计一个程序,对任意设定的迷宫,求出一条从入口到出口的通路,或得出没有合适通路的结论。

 

302. 队列--旅行家的预算

一个旅行家想驾驶汽车以最少的费用从一个城市A到另一个城市B(假设出发时油箱是空的)。给定两个尘世直接的距离D1、汽车油箱容量C(以升为单位)

 

 

303. 链表--约瑟夫问题

N个人围成一圈,从第一个人开始报数,第M个将被杀掉,依次进行,最后只剩下一个,其余人都将被杀掉。这就是著名的约瑟夫问题。请用C代码实现该问题,要求被杀掉的顺序依次打印(包含最后剩余的一个)。

 

304. 二叉树遍历

下面代码实现的是一个遍历二叉树函数,并打印每一个节点,请补全空白处代码。

struct TreeNode{
    struct TreeNode* left;
    struct TreeNode* right;
    int val;
};

struct Stack{
    struct TreeNode* node;
    int flags;
};

void Process(struct TreeNode* root)
{
    struct Stack stack[MAX_STACK];
    struct TreeNode* cur = root;
    int top = 0;
    
    while(cur || top > 0)
    {
        if(cur)
        {
            stack[top].node = cur;
            stack[top++].flags = 0;
            cur = cur->left;
        }
        else if(________)
        {
            cur = stack[--top].node;
            PrintNode[cur];
            ______________;
        }
        else
        {
            cur = Stack[top - 1].node;
            Stack[top - 1].flags = 1;
            ______________;
        }
    }
}

 

305. Modbus CRC

 Modbus协议是应用于电子控制器上的一种通用语言。

 

306. 汉诺塔问题

请用C代码实现汉诺塔问题。

 

307. 找符合规则的数

 给定函数D(n) = n + n的各位之和,n为正整数

 

308. 二分法查找

 用C语言编程,编写一个函数实现查找功能。

 

309. Hash查找

用C语言编写一个字符串查找程序,其功能是在输入若干个单词后查找出现频率最高的一个单词(每个单词最长不超过20个字母)。

 

310. 选择排序

选择排序是常见的一种排序算法。其基本思想是:每步从待排序的记录中选出排序码最小(或最大)的记录,顺序存放在已排序的记录系列的后面,直到全部排完。请用C语言实现选择排序算法。

 

311. 冒泡排序

请用C语言实现冒泡排序算法。冒泡排序算法是针对待排序记录的关键字的每相邻两个元素进行比较,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。

 

312. 插入排序

请用C语言实现插入排序算法。

 

313. 快速排序

请用C语言实现快速排序算法。

 

314. Colored Cubes

 You have four colored cubes.

 

 

第四章 程序的基本单位--函数

 

401. 函数声明与定义

请举例说明函数的声明与定义的区别。

 

402. 十六进制转十进制

请写一个函数,实现将以字符串形式存放的十六进制数转换为一个十进制数(非负整数),输入的十六进制字符串最长为8个字节(不包含‘\0’结束符)

函数原型可定义为:

unsigned int hexToDec(const char* hex, int n);

 

403. 函数纠错

请指出该函数存在哪些问题。

char* func()
{
    char* a;
    a = (char*)malloc(5);
    strcpy(a, "ABCDE");    
    a = "CDE";
    return a;
}

 

404. 找出子串的个数

请写出 一个函数,完成在一个字符串中查找子字符串出现次数的功能。

 

405. 指针函数与函数指针

请说出指针函数与函数指针的区别。

答案:指针函数是指函数的返回值是指针类型,其本质是一个函数;函数指针是指函数的入口地址,其本质是一个指针变量。

 

406. 回调函数

请利用回调函数机制写一个整数排序算法

 

407. 可变参数函数

请设计一个可变参数的函数,找出N个数中最大的一个。

 

408. 函数调用

请举例说明函数的调用过程。

 

409. 内联(inline)函数

请举例说明内联(inline)函数与宏定义的区别。

 

410. main()函数的命令行参数

下面main()函数命令行参数表示形式不合法的是()

 

411. hexdump()函数

编写一个C函数,函数功能要求是:给定一个内存地址和要打印内容的长度,打印这段内存区域的内容,打印的内容包含内存地址值、以十六进制ASCII码表示的内存内容、字符形式的ASCII码。

 

412. Sequence of Function Execution

 Please select the correct result:

 

413. 调试相关宏

请问C库中这几个宏__FILE__、__LINE__和__func__的意义及其用法。

 

414.大小写字母转换

请写一段程序,完成将字符串中的小写字母转换为大写字母的功能。

 

415. 文件操作

请写一段程序,实现在指定的文件中查找匹配特定的字符串,并打印出该行的内容以及所在的行号。

 

416. 数学库

已知一个圆的面积为CA,求该圆内最大正方形的面积SA。

 

417. All Combinations of a Word

Write a C program for all possible combinations of letters in a word, no need repeated combinations.

 

 

第五章 数据的传递--网络

 

501. 网络字节序

请说明为什么在网络中要使用网络字节序?

答案:统一不同平台的字节序

 

502. IP地址转换

请写一段程序讲一个字符串形式的IP地址转换为一个以网络字节序存放的整数,设定开发系统为Little-Endian字节序,不能使用系统调用函数实现

 

503. 设计数据报文头结构

请设计一个数据包头的结构体,该数据包头包含:

 

504. IP头校验和

为了计算一份数据报的IP头校验和,首先把校验和字段置0。

 

505. RC4 Algorithm

RC4 is simple to describe.

 

506. 解析URL

已知URL的格式为“protocol://hostnaem:port”

 

507. 实现简单Ping命令

请说明ping命令在系统中的作用,以及在Linux系统中如何实现一个不带选项的ping功能,请写出实现该功能的核心代码。

 

508. 实现HTTP GET

请用socket编程实现HTTP GET请求,

 

509. Blocking 和 Non-Blocking

请问在socket编程中,blocking模式主要用在什么地方?如何创建一个Non-blocking模式的socket?

 

510. select()函数的用法

请使用C/S(Client/Server)架构实现一个程序,程序的功能为:

 

511. fork()与pthread_create()

请举例说明由fork()创建的进程与pthread_create()创建的线程有什么区别?

 

512. SYN洪流攻击

SYN洪流(flood)攻击是Dos攻击的一种

 

 

第六章 专用的计算机系统--嵌入式

 

601. 对寄存器的位操作

假定一个寄存器的值由整数变量R表示,写两个数,第一个设置R的bit N(0 < N < 31),第二个清除R的bit N。在以上两个操作中,要保持其他位不变。

 答案:

R1 = R1 | (1 << N);
R1 = R1 & (~(1 << N));

 

602. register关键字

请问C语言中register关键字的作用是什么?

答案:申请把变量存入寄存器。

 

603. *(volatile unsigned long)0xfff40080

请分析下述代码中volatile的含义

int v;
v = *(volatile unsigned long*)0xffff40080;

 答案:告诉编译器,这个修饰的值或地址指向的值随时会发生变化,每次使用时都要去内存里重新读取它的值。

 

604. #ifdef、#if、#if defined和#ifndef

 请举例说明#ifdef、#if、#if defined和#ifndef的用法及作用

答案:#ifdef、#if、#if defined和#ifndef用于条件编译。

 

605. -1在内存中的表示

 已知printf("0x%X, 0x%X",-1,, (-1<<2));,请问改行代码的输出是哪一个?()

A. 0xFFFFFFFF, 0XC         B. 0xFFFFFFFF, 0xFFFFFFFC         C.0xFFFFFFFF, 0xFFFFFFF4

 答案:B

 

606. 找出重复的数

 已知含有N个元素的一个数组,数组中各元素值的范围是1~N-1,找出重复的那个值。

 

607. #define中的“##”与“#”

已知

#define test(n) printf("test"#n"= %d", test##n);

请说明该代码中“#”与“##”的含义。

答案:“#”用来把参数转换为字符串;“##”用来连接前后两个参数,把它们变成一个字符串。

 

608. 计算一个整数中含1的比特数

编写一个函数,实现功能为:输入一个无符号整数,计算出该整数中含1的比特个数。如给定一个整数8(二进制为1000),它含1的比特数为1。

 

609. 递归运算

下述代码的输出是()

int foo(int x, int y)
{
    if((x <= 0) || (y <= 0))
    {
        return 1;
    }
    
    return (3 * foo(x - 1, y / 2));
}

int main()
{
    printf("%d\n", foo(3, 5));
    
    return 0;    
}

答案:27

 

610. 数值溢出运算

请问指向如下一段代码后, sum的值是多少?

char chr = 127;
int sum = 100;

chr += 1;
sum += chr;

答案:-28

 

611. 定义boolean类型

boolean类型用于表达一个逻辑的结果为真或假(1或0),假设目前C语言中没有boolean数据类型,请用代码定义一种boolean类型。

答案:

typedef enum {FALSE, TRUE} boolean;

 

612. for()、while()与do{}while()

请说明for()、while()与do{}while()的区别。

 

613. 位域应用

请分析下述程序的运行结果是()

union 
{
    struct 
    {
        unsigned char c1:3;
        unsigned char c2:3;
        unsigned char c3:2;
    } s;
    unsigned char c;
} u;

int main()
{
    u.c = 100;
    
    printf("%d\n", u.s.c1);
    printf("%d\n", u.s.c2);
    printf("%d\n", u.s.c3);
    
    return 0;
}

答案:4 4 1

 

614. break与continue的区别

请举例说明C语言中break与continue语句的用法与区别。

答案:break跳出循环体,continue结束本次循环。

 

615. 指针偏移计算

分析下述程序的结果输出,并给予解释。

struct DATA
{
    long num;
    char* name;
    short int data;
    char ha;
    short ba[5];
}* p; 

int main()
{
    p = (struct DATA*)0x10000000;
    printf("%p\n", p + sizeof(*p));
    printf("%p\n", p + 1);
    printf("%p\n", (unsigned long)p + 1);
    printf("%p\n", (int*)p + 1);
    printf("%p\n", (char*)p + 1);
return 0;
}

答案:0x10000240 0x10000018 0x10000001 0x10000004 0x10000001

 

616. 判断链表是存在环

请实现一个函数,该函数用于判断一个单向链表中是否存在环(即链表元素练成了环)。该函数原型定义为:int LinkIsCircle(Link* pHead);,参数pHead为要判断的链表头结点;有环返回1,没有环返回0。

答案:双指针遍历

 

617. const与指针

已知有如下4中方式定义指针变量p,请说明这4个变量p的含义。

char* const p;
char const* p;
const char* p;
const char* const p;

答案:左数右指

 

618. 指向绝对地址执行

在某一函数调用中,期望程序从内存地址0x200000执行,请问如何写这样的代码?

答案:

typedef void(FUNC*)();
*((FUNC)0x200000)();

 

619. 同名变量(全局变量与局部变量)

请分析下述代码的输出结果。

int x = 0;

int ModifyValue()
{
    return (x += 10);
}

int ChangeValue(int x)
{
    return (x += 1);
}

int main()
{
    int x = 10;
    
    x++;
    
    ChangeValue(x);
    
    x++;
    
    ModifyValue();
    
    printf("First output: %d\n", x);
    
    x++;
    
    x = ChangeValue(x);
    
    printf("Second output: %d\n", x);
    
    x = ModifyValue();
    
    printf("Third output: %d\n", x);
        
    return 0;
}

答案:12 14 20

 

620. gets()与fgets()

请举例说明gets()与fgets()库函数的区别。

答案:gets()与fgets()函数的原型如下,

char* fgets(char* s, int size, FILE* stream);
char* gets(char* s);

 

621. 头文件重复引用

通常在头文件中可以看到如下的形式:

#ifndefine _HEADFILE_H_
#define _HEADFILE_H_

...

#endif

 

622. u8、u16、u32和u64

在嵌入式编程中,经常会看到u8、u16、u32和u64的数据类型,请问他们代表的意义是什么?为什么要这么写?

答案:一般在x86体系的Linux系统中,u8、u16、u32和u64的数据类型定义如下

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;

这样写的原因

① 编写代码方便

② 提高代码的可移植性

 

623. 条件编译

已知整数(4字节)在内存中的内容,打印出该整数实际的值,请用C语言实现。

 

624. 转义字符问题

请问下述代码是否存在问题,为什么?

#ifndef __MSDOS__
const char name[] = "/root/new/table";
#else
const char name[] = "\root\new\table";
#endif

答案:C语言中,'\r'代表回车,‘\n’代表换行,‘\t’代表一个Tab。

 

625. 提高可移植性常见技巧

请说出一些可提高C语言移植性的实用技巧。

 

626. i--与i<10

请比较for(i = 0; i < 10; i++)与for(i = 10; i--;)循环语句的效率。

 

627. switch代替if...else...

 对多个分支条件实用if...else...语句还是switch语句效率较高?

答案:switch语句

 

628. 代码优化常见技巧

请说出至少5中优化C代码的技巧。

 

629. 模拟Modbus协议

在嵌入式系统开发中,Modbus协议是工业控制系统中广泛应用的一种协议。

 

转载于:https://www.cnblogs.com/wulei0630/p/10400560.html

你可能感兴趣的:(经典C面试真题精讲)