2012-6-27日下午,去了一个软件公司笔试面试,3道题目,都是 C 语言的编程题,题意简单明了,写起来好麻烦,而且是在纸上写的,平常习惯了写写改改,后来发现整个卷面乱的真不是给人看的。
第一题:将n个文件合并到一个文件中,要求保存每个文件的文件名,文件长度,文件数据。函数签名 int fpack(const char *flist[], const char *dstfile); flist的形式 {"1.doc", "2.txt", "3.exe", NULL} 。第一题就难倒我了,首先是要读写二进制文件,fread, fwrite本身就用的不多,又有4个参数,参数 File * 在第一个还是在第四个常搞不清楚,且第二个参数和第三个参数容易混淆;文件长度要通过读文件数据才知道,那么文件头信息中的文件长度还不能一开始就写入,需要 fseek 来回定位,当时就直接看第2题和第3题了,最后回过头了,硬着头皮写完了这个函数,现在回来仔细想想当时写得真是漏洞百出啊,于是又重新写了一遍:
1 #include <stdio.h> 2 #include <string.h> 3 4 struct SFile { // 注意边界对齐,f_name[6] 与 f_name[8] 时,sizeof(SFile) 都等于12 5 int f_len; // 感觉 f_len 应该写在 f_name 前面比较好 6 char f_name[8]; 7 }; 8 9 void print_buf(const char *buf, int len) { 10 for (int i = 0; i < len; ++i) 11 printf("%X", buf[i]); 12 puts(""); 13 } 14 15 int fpack(const char *flist[], const char *dstfile) { 16 int n = 0; 17 const char **p = flist; 18 char buf[1024]; 19 int len = 0; 20 SFile file; 21 22 for (; *p != NULL; ++p, ++n) ; // 统计需要 pack 的文件个数 23 24 FILE *pDst = fopen(dstfile, "wb"); 25 if (pDst == NULL) { 26 puts("pDst fopen error!"); 27 return -1; 28 } 29 30 printf("n = [%d]\n", n); // 31 fwrite(&n, sizeof(n), 1, pDst); // 文件前siezof(int)个字节保存文件的个数 32 33 for (p = flist; *p != NULL; ++p) { // 遍历每个文件 34 printf("f_name = [%s]\n", *p); 35 strcpy(file.f_name, *p); // 构造结构体 36 file.f_len = 0; 37 38 FILE *pf = fopen(*p, "rb"); // 打开文件 39 if (pf == NULL) { 40 puts("pf fopen error!"); 41 fclose(pDst); 42 return -1; 43 } 44 45 fseek(pDst, sizeof(SFile), SEEK_CUR); // 跨越文件头信息,先写文件数据 46 while ((len = fread(buf, 1, 1024, pf)) > 0) { // 注意不能写成 fread(buf, 1024, 1, pf),否则 len 为 0 47 printf("len = [%d]\n", len); // 48 print_buf(buf, len); // 49 file.f_len += len; // 更新文件长度数据 50 fwrite(buf, 1, len, pDst); 51 } 52 53 int sz1 = sizeof(SFile); 54 int sz2 = file.f_len; 55 printf("sz1 = [%d], sz2 = [%d]\n", sz1, sz2); // 56 printf("fn = [%d], fl = [%d]\n", sizeof(file.f_name), sizeof(file.f_len)); 57 58 fseek(pDst, -(sz1 + sz2), SEEK_CUR); // 回到写文件头信息的位置 59 fwrite(&file, sz1, 1, pDst); // 写入头信息 60 fseek(pDst, 0, SEEK_END); // 定位到文件尾,为下一个文件做准备 61 62 fclose(pf); // 关闭当前文件 63 } 64 65 fclose(pDst); // 关闭目标文件 66 return 0; 67 } 68 69 int main(int argc, char *argv[]) 70 { 71 const char *s[8] = {"111.txt", "222.txt", "333.txt"}; 72 const char *d = "d.txt"; 73 74 printf("iRet = %d\n", fpack(s, d)); 75 76 return 0; 77 }
运行结果如下:
就算去掉注释,也最起码要50行,一面A4纸还真不一定能写下,何况纸上涂改是必然的。
第三题:将一个带头结点的单链表转换成一个带头结点的双向循环链表,这个题目不仅要满足是双向链表,还要满足循环链表,从单链表直接跳了两步,但是和第一题、第二题比起来,对我来说或许还能折腾出来,于是就先写了此题,回来在机器来又找原来写了遍,测试了下基本没有出错,如下:
1 #include <malloc.h> 2 #include <stdio.h> 3 4 struct Node { 5 int data; 6 Node *next; 7 }; 8 9 struct BiNode { 10 int data; 11 BiNode *next; 12 BiNode *prev; 13 }; 14 15 BiNode *convert(const Node *head) { // 假定内存足够,malloc不会失败 16 BiNode *pBh = (BiNode *)malloc(sizeof(BiNode)); // 双向循环链表头结点 17 pBh->data = 0; 18 pBh->next = pBh->prev = NULL; // 默认置空 19 20 BiNode *q = NULL; 21 Node *p = head->next; 22 23 if (p != NULL) { // 单链表不为空 24 q = (BiNode *)malloc(sizeof(BiNode)); 25 q->data = p->data; 26 q->next = q->prev = q; // 双向循环链表只有一个结点的时候,next 和 prev 均指向自己 27 pBh->next = pBh->prev = q; // 头结点两个指针均指向第一个结点 28 29 p = p->next; 30 for (; p != NULL; p = p->next) { // 遍历单链表余下的结点 31 BiNode *t = (BiNode *)malloc(sizeof(BiNode)); 32 t->data = p->data; 33 t->next = q->next; 34 t->prev = q; 35 36 q->next = t; // 原来的尾结点next指向新的尾结点 37 pBh->next->prev = t; // 第一个结点prev指向新的尾结点 38 39 q = t; // q 保持指向尾结点 40 } 41 } 42 43 return pBh; 44 } 45 46 void print_clockwise(const BiNode *h) { 47 const BiNode *p = h->next; // 第一个结点 48 printf("data = [%d]\n", p->data); 49 50 p = p->next; 51 for (; p != h->next; p = p->next) 52 printf("data = [%d]\n", p->data); 53 54 puts("----"); 55 } 56 57 void print_anticlockwise(const BiNode *h) { 58 const BiNode *p = h->next; // 第一个结点 59 printf("data = [%d]\n", p->data); 60 61 p = p->prev; 62 for (; p != h->prev; p = p->prev) 63 printf("data = [%d]\n", p->data); 64 65 puts("----"); 66 } 67 68 int main(void) 69 { 70 // 构造单链表 71 Node n[5]; 72 Node *head = &n[0]; 73 head->data = 0; 74 head->next = &n[1]; 75 n[1].data = 1; 76 n[1].next = &n[2]; 77 n[2].data = 2; 78 n[2].next = &n[3]; 79 n[3].data = 3; 80 n[3].next = &n[4]; 81 n[4].data = 4; 82 n[4].next = NULL; 83 84 BiNode *pBh = convert(head); 85 86 // 顺时针打印 87 print_clockwise(pBh); 88 89 // 逆时针打印 90 print_anticlockwise(pBh); 91 92 return 0; 93 }
运行结果如下:
哗啦哗啦又是90行,A4纸很紧张啊~~!