几道C笔试题

Q:printf和scanf的返回值是什么?数组

复制代码
int main()  
{  
    int i = 43;  
    int n = printf("%d\n",i);
    printf("%d\n",n);     
    return 0;
} 
复制代码

A:printf函数返回3。因为其输出了'4', '3', '\n' 三个字符。多线程


printf返回的是成功输出到STDOUT的字符数。假设错误发生,返回一个负数。函数


scanf返回的是成功赋值的变量个数,假设错误发生,返回EOFpost

Q:既然fgetc是接收输入的字符,返回值用char或者unsigned char不便可了,为何用int呢?
A:这个主要是因为文件结束或者读写文件出错的标志被规定成EOF。也就是-1致使的。unsigned char根本取不到-1这个值。而假设用char作返回值的话,它没法分辨0xFF字符和EOF。因为这两个数值都被char以为是-1,因此它也不能做为返回值。优化

Q:此段程序但愿输出数组中的所有元素。但却没有获得想要的结果,是什么产生歧义?spa

复制代码
#include <stdio.h> 
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0])) 
int array[] = {23,34,12,17,204,99,16}; 
int main() 
{
    int d;
    for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
        printf("%d\n",array[d+1]);
    return 0; 
} 
复制代码

A:执行上面的程序。结果是什么都没有输出,致使这个结果的缘由是sizeof的返回值是一个unsinged int,为此在比較int d 和TOTAL_ELEMENTS两个值都被转换成了unsigned int来进行比較,这样就致使-1被转换成一个很大的值,以致于for循环不知足条件。所以,假设不能理解sizeof操做符返回的是一个unsigned int的话,就会产生相似如上的歧义。.net

Q:如下这段程序的输出结果是:线程

复制代码
#include <stdio.h> 
#define f(a,b) a##b 
#define g(a)   #a 
#define h(a) g(a)   
int main() 
{
    printf("%s\n", h(f(1,2)));
    printf("%s\n", g(f(1,2)));
    return 0; 
} 
复制代码

A:在C语言的宏中,#的功能是将其后面的宏參数进行字符串化操做(Stringfication)。而##被称为链接符(concatenator)。用来将两个Token链接为一个Token。
看到这段程序你可能会以为,这两个printf输出的同一个结果,可是答案却非如此。本题的输出是12和f(1,2)。为何会这样呢?因为这是宏。宏的解开不象函数运行那样由里到外。#将右边的參数作整体的字符串替换,即使是还有一个宏,也不展开,因此,g(f(1,2))->"f(1,2)"。指针

对于h(f(1,2)),因为h(a)是非#或##的普通宏。需要先宏展开其參数a,即展开f(1,2)为12,则h(a) 宏替换为h(12)。进而宏替换为g(12), 进而宏替换为"12"。code

Q:假如咱们的a的地址是:0Xbfe2e100, 而且是32位机,那么这个程序会输出什么?

复制代码
#include <stdio.h>
int main()
{
    int a[5];
    printf("%x\n", a);
    printf("%x\n", a+1);
    printf("%x\n", &a);
    printf("%x\n", &a+1);
    return 0;
}
复制代码

A:
第一条printf语句应该没有问题,就是 bfe2e100。 
第二条printf语句你可能会觉得是bfe2e101。那就错了。a+1。编译器会编译成 a+ 1*sizeof(int),int在32位下是4字节。因此是加4,也就是bfe2e104。
第三条printf语句多是你最头疼的。咱们怎么知道a的地址?我不知道吗?可不就是bfe2e100。那岂不成了a==&a啦?这怎么可能?本身存本身的?或许很是多人会认为指针和数组是一回事,那么你就错了。假设是 int *a,那么没有问题,因为a是指针。因此 &a 是指针的地址,a 和 &a不同。但是这是数组啊a[],因此&a事实上是被编译成了 &a[0]。 
第四条printf语句就很是天然了。就是bfe2e104。仍是不正确,因为是&a是数组,被当作int(*)[5]。因此sizeof(a)是5,也就是5*sizeof(int)。也就是bfe2e114。

Q:例如如下代码为何结果始终不正确?

复制代码
#include <stdio.h>
int main()
{
    int a = 2;
    if(a & 1 == 0)
        printf("a & 1 == 0");
    else
        printf("a & 1 != 0");
    return 0;
}
复制代码

为何输出“a & 1 != 0”?
A:这是因为==的优先级高于表示位与运算符&.因此a & 1 == 0的实际代码是a & (1 == 0)。也就是a & 0, 固然结果不是预期了。

(优先级:==和!= 高于 & 高于 ^ 高于 | 高于 && 高于 || )。

优先级从高到低:算术运算符,位移运算符,关系运算符,位操做& ^ |

Q:例如如下代码输出什么?

复制代码
int main()
{
    int i = 6;
    if( ((++i < 7) && ( i++/6)) || (++i <= 9));
        printf("%d\n",i);
    return 0;
}
复制代码

A:8。本题主要考的是&&和||的短路求值的问题。所为短路求值:对于(条件1 && 条件2)。假设“条件1”是false,那“条件2”的表达式会被忽略了。对于(条件1 || 条件2),假设“条件1”为true,而“条件2”的表达式则被忽略了。

Q:sizeof后面可以跟表达式,如下的代码,为何i++无效呢?

复制代码
#include <stdio.h>
int main()
{
    int i = 1;
    sizeof(i++);
    printf("%d\n", i);
    return 0;
}
复制代码

执行结果:1
A:正因为sizeof是编译期求值的,因此假设它跟着表达式,那么表达式是不被计算的,仅仅是根本表达式的类型获得它占用的空间。

Q:如下的程序试图使用“位操做”来完毕“乘5”的操做,只是这个程序中有个BUG,你知道是什么吗?

复制代码
#include <stdio.h>
#define PrintInt(expr) printf("%s : %d\n",#expr,(expr))
int FiveTimes(int a)
{
    int t;
    t = a<<2 + a;
    return t;
}
int main()
{
    int a = 1;
    PrintInt(FiveTimes(a));
    return 0;
}
复制代码

A:本题的问题在于函数FiveTimes中的表达式“t = a<<2 + a;”,对于a<<2这个位操做,优先级要比加法要低,因此这个表达式就成了“t = a << (2+a)”,因而咱们就得不到咱们想要的值。

该程序修正例如如下:“t = (a<<2) + a;”

Q:例如如下代码关于位运算符的操做为什么终于结果和预期不符?

复制代码
#include <stdio.h>
int main()
{
    unsigned char c = 0xfc;
    unsigned int i = ~c;
    printf("%x\n",i);
    return 0;
}
复制代码

执行结果:0xffffff03
依照上面的代码,~c应该获得的是0x03, 那么结果应该是0x03, 怎么会是上面的结果呢?
A:这是因为位运算是被提高到整形运算的。

上面的变量c是无符号字符型,在进行~位运算时,是首先提高为整形,即为0x000000fc, 而后取反获得0xffffff03, 因此i获得的数值是这个。同理。假设c是char类型。提高为整形时为0xfffffffc。再取反获得的就是0x03。事实上变量被提高有很是多地方。比方short计算时也会提高为int再继续计算。

Q:如下这个程序运行后会有什么错误或者效果:

复制代码
#define MAX 255
int main()
{
    unsigned char A[MAX];
    unsigned chat i;
    for (i = 0; i <= MAX; i++)
        A[i] = i;
}
复制代码

A:MAX=255,数组A的下标范围为:0..MAX-1,下标越界。当i循环到255时。循环内运行: A[255]=255;这句自己没有问题,但是返回for(i=0;i<=MAX;i++)语句时。由于unsigned char的取值范围在[0,255]。i++之后i又为0了,无限循环下去。
注意:char类型为一个字节,取值范围是[-128,127],unsigned char取值范围[0,255]

Q:有a和b两个整型变量,不用“if”,“? :”,“switch”或者是其它推断语句,怎样获得大者和小者?
A:大者:((a+b)+abs(a-b))/2
   小者:((a+b)-abs(a-b))/2

Q:请定义一个宏,比較两个数a、b的大小。不能使用大于、小于、if语句
A:可以推断两个数相减后的符号,32位整数相减后的符号位:

#define MAX(a,b)  ((((a)-(b))&(1<<31))?

(b):(a))

Q:定义一个宏,求一个结构体struct中某个变量相对于struct的偏移量

A:#define OFFSET(struct, member)  ((unsigned int)&((struct *)0)->member)

Q:求不小于x的最小的2的K次方的数:

复制代码
int pow2_ceil(unsigned int x)
{
    x--;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    x++;
    return x;
}
复制代码

灵活的位操做可以有效地提升程序执行的效率: 
1.设置x的bit5为1,其它位不变:x |= (1<<5);
2.设置x的bit5为0。其它位不变:x &= ~(1<<5);
3.推断x的bit5是否为1。(x & (1<<5)) != 0 ?

1:0;
4.推断一个数是否是偶数:(num & 1) == 0 ? 1:0;

关于C中volatilekeyword的做用:一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样。编译器就不会去若是这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都当心地又一次读取这个变量的值,而不是使用保存在寄存器里的备份。
如下是volatile变量的几个样例:
     1). 并行设备的硬件寄存器(如:状态寄存器)
     2). 一个中断服务子程序中会訪问到的非本身主动变量(Non-automatic variables,本身主动变量是auto或register变量)
     3). 多线程应用中被几个任务共享的变量:volatile keyword告诉编译器不要持有变量的暂时性拷贝。

请看下面情形:A线程将变量复制入寄存器,而后进入循环,重复检測寄存器的值是否知足必定条件。它期待B线程改变变量的值。在此种状况下,当B线程改变了变量的值时。已改变的值对其在寄存器的值没有影响。因此A线程进入死循环。

几道C笔试题
相关文章
相关标签/搜索