本文将持续更新C经典面试题笔试题,短短的程序,却是大大的有意思。如果你针对文中内容有不同见解,欢迎留言评论.本文将会持续更新,记录有意思的题目。
以下程序的输出为:

#include <stdio.h>
int main()
{
    float a=5.2;
    if(a==5.2)
        printf("equal");
    else if(a < 5.2)
        printf("less than");
    else
        printf("Great than");
    
    return 0;
}

首先我们看知乎网友vczh的精彩回复:
一般来讲,==和!=在针对浮点数的时候,两边都必须是字面量。意思就是,左边是1.0,右边是1.0,他们中间复制了几次,总之只要他们不是被计算出来的,可以比较。但是如果是计算出来的——可没有人告诉你0.1+0.1就是0.2。0.1这个值其实是不存在的,因为它不能被处理成一个2进制的有限小数。所以你对两个不存在的值进行相加,就会得到一些奇怪的误差,所以才不能==。到底0.1+0.1和0.2相比,到底是谁大谁小还是一样,完全取决于你的C++编译器在对付2进制无限小数的时候,到底用什么样的截断策略——譬如说ceil、floor、round,都是有可能的。如果这个策略你已经清楚了,那你自己也可以判断到底是什么结果。反过来,只要是精度以内的二进制有限数字就可以。譬如说,0.25+0.25,肯定就==0.5,没有问题。
针对上面的回复几点解析:
精确表示的数字比如0 0.5 0.25 0.125等以及这些能够表示的数字的任意位数相加,比如0.5+0.125能够精确表示,0.5对应二进制0.1,0.125对应二进制0.001,那么十进制0.1就无法用二进制精确表示,因此针对浮点数相等在无法精确表示的情况下不能使用==来判断两者是否相等。
验证程序:

#include <stdio.h>
int main()
{
    float f=0.25;
    
    if(f < 0.25)
        printf("f less than 0.25.\n");
    else if (f > 0.25)
        printf("f greater to 0.25.\n");
    else
        printf("f equal to 0.25.\n");
    
    float g=0.1;
    
    if(g < 0.1)
        printf("g less than 0.1.\n");
    else if (g > 0.1)
        printf("g greater to 0.1.\n");
    else
        printf("g equal to 0.1.\n");
    
    /*字面值常量可以直接比较,不是通过计算得来的数据或者存储在变量之中.*/
    if(5.2 ==5.2)
        printf("eqaul\n");
    return 0;
}

输出内容为:
f equal to 0.25.
g greater to 0.1.
equal

下面程序的输出为:

int main()
{
    int a=2;
    if(a==2)
    {
        a= ~a+2 <<1;
        //执行优先级为a= (~a+2) <<1;
        printf("%d",a);
    }
    return 0;
}

这道题首先还是数组存储方面的知识,~a取反加上2后,存储为1……1(32个1,假设32位系统),然后左移一位右侧补零,于是为-2.
以下程序的输出为:

#include<stdio.h>
int main()
{
    int a = 320;
    char *c = &a;
    printf("%d\n",*c);
    return 0;
}

320的二进制形式为:101000000, 0x00000140(32位)。
举一个例子,比如数字0x12345678在内存中的表示形式为:
1)大端模式:
低地址 -----------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
2)小端模式:
低地址 ------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
可见,大端模式和字符串的存储模式类似。一般操作系统为小端模式。
因此在小端模式系统中程序输出为64.大端模式系统中程序输出为1

以下程序是否存在问题:

#include <stdio.h>
#include <string.h>

struct outer
{
    int a;
    struct inner
    {
        char c;
    };
};

int main()
{
    struct outer var;
    var.a = 10;
    var.inner.c = 20;
    return 0;
}

Xcode中相关提示如下:

It is necessary to assign name of innerstructure at the time of declaration otherwise we cannot access the member of innerstructure.
因此正确的代码如下:

#include <stdio.h>
#include <string.h>

struct outer
{
    int a;
    struct inner
    {
        char c;
    }name;
};

int main()
{
    struct outer var;
    var.a = 10;
    var.name.c = 20;
    return 0;
}

new和malloc的区别:
两篇总结的比较好的文章:
new与malloc的区别

What is the difference between new/delete and malloc/free?
stackoverflow上比较精炼的回答:
There are other differences:
new is type-safe, malloc returns objects of type void*
new throws an exception on error, malloc returns NULL and sets errno
new is an operator and can be overloaded, malloc is a function and cannot be overloaded
new[], which allocates arrays, is more intuitive and type-safe than malloc
malloc-derived allocations can be resized via realloc, new-derived allocations cannot be resized
malloc can allocate an N-byte chunk of memory, new must be asked to allocate an array of, say, char types
当malloc申请内存失败时会设置errno,验证程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
    /*申请海量内存,构造申请失败,查看errno*/
    int *p = (int *)malloc(10000000000000000*sizeof(int));
    if(NULL == p)
        printf("errno =%d,%s\n",errno,strerror(errno));
    return 0;
}

程序输出:
errno =12,Cannot allocate memory

malloc与free中申请与释放内存的解释:
1.对一个非空指针free多次,结果未定义,也即任何事情都是有可能发生的,如果运气不好,硬盘被格式化掉都是可能的。

2.对空指针free多次,就不会报错;
一个好的习惯是:在用delete 或用free 释放p 所指的内存后,应该马上显式地将p 置为NULL,以防下次使用p 时发生错误。在声明指针时对指针初始化,如果暂时不用,要将指针置空。
为什么释放之后要置为NULL呢?我们看下man手册中的解释:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
如果ptr是NULL,什么都不做。

fread与read区别

fread与read的区别,同样的问题还有fwrite与write区别。
答案:
fread fwrite是ANSI的C标准库。而read与write是UNIX下的系统调用。
fread带有缓冲,是read的衍生,或者说fread是通过read实现的,要想直接和硬件打交道,必须用read.
read() is a low level, unbuffered read. It makes a direct system call on UNIX.

fread() is part of the C library, and provides buffered reads. It is usually implemented by calling read() in order to fill its buffer.
What is the difference between read() and fread()?

给出如下描述中的定义

a) 一个整型数(An integer)
b)一个指向整型数的指针( A pointer to an integer)
c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)
d)一个有10个整型数的数组( An array of 10 integers)
e) 一个有10个指针的数组,该指针是指向一个整型数的。(An array of 10 pointers to integers)
f) 一个指向有10个整型数数组的指针( A pointer to an array of 10 integers)
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument and returns an integer)
h) 一个有10个指针的数组,每个指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer )
答案:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
最后一个例子的验证程序如下:

#include <stdio.h>

int f(int a)
{
    return a;
}

int g(int a)
{
    return 2*a;
}

int main()
{
    int (*a[10])(int);
    

    a[0] = &f;
    a[1] = &g;
    printf("%d\n",a[0](10));
    printf("%d\n",a[1](10));
    return 0;

}

程序输出
10
20

什么事预编译,何时需要预编译

答:预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等,就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
c编译系统在对程序进行通常的编译之前,先进行预处理。c提供的预处理功能主要有以下三种:1)宏定义 2)文件包含 3)条件编译
gcc编译阶段

写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。

答:
BOOL : if ( !a ) or if(a)
int : if ( 0 == a)
float : const EXPRESSION EXP = 0.000001
if ( a < EXP && a >-EXP)
pointer : if ( a != NULL) or if(a == NULL)

用两个栈实现一个队列的功能

用两个栈s1和s2模拟一个队列时,s1作输入栈,逐个元素压栈,以此模拟队列元素的入队。

当需要出队时,将栈s1退栈并逐个压入栈s2中,s1中最先入栈的元素,在s2中处于栈顶。

s2出栈,相当于队列的出队,实现了先进先出。

显然,只有栈s2为空且s1也为空,才算是队列空。
[算法讨论]算法中假定栈s1和栈s2容量相同。出队从栈s2出,当s2为空时,若s1不空,则将s1倒入s2再出…