• C/C++ 笔试,难倒我哉


      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纸很紧张啊~~!

  • 相关阅读:
    【文章阅读】计算机体系-计算机将代码编译和持续运行过程中需要考虑的问题,以及具体的实现原理讲解
    JAVA性能调试+JProfiler使用相关
    【2016.10.30】王国保卫战-安卓汉化版
    【2017.01.05】装系统教程
    【2016.11.10】百度云离线下载迅雷链接
    mongodb 杂记
    缓存使用思路
    分布式 vs 集群
    切面 aop 笔记
    前端
  • 原文地址:https://www.cnblogs.com/nysanier/p/2566389.html
Copyright © 2020-2023  润新知