zoukankan      html  css  js  c++  java
  • c语言面试常见题

    一、typedef

    为现有类型创建一个新的名字, 使用最多的地方是创建易于记忆的类型名
    typedef int size;此声明定义了一个 int 的同义字,名字为 size

    想看http://baike.baidu.com/view/1283800.htm

    12:考查typedef类型定义,函数指针

    1typedef int (*test) ( float * , float*)
    test tmp;

     tmp 的类型是
    (a) 函数的指针,该函数以 两个指向浮点数(float)的指针(pointer)作为参数(arguments)
          Pointer to function of having two arguments that is pointer to float
    (b) 整型
    (c) 函数的指针,该函数以 两个指向浮点数(float)的指针(pointer)作为参数(arguments),并且函数的返回值类型是整型 
          Pointer to function having two argument that is pointer to float and return int
    (d) 以上都不是

    另外一例:

    typedef void*ptr_tp_func(int);/*它表示ptr_tp_func是函數指針,該函數接受一個int參數,返回值為void*/

    ptr_tp_func signal(int, ptr_tp_func);/*表示signal是一個函數,接受兩個參數,一個int和一個ptr_tp_func,返回值是ptr_tp_func類型*/

    二、按位运算小技巧

    1统计i有多少位为1for( ; i ; i&=i-1) k++;

    2宏写出swap(x,y)

     #define swap(x,y)

          x=x+y;      y=x-y;      x=x-y;

    3、一句实现判断x是不是2的若干次幂:x&(x-1)false:true;

    4、实现左移循环移n位:a=(a<<n)|(a>>(8*sizeof(int)-n));

    5、快速求一个数的7倍:X<<3-X

    三、编译宏

          #define     定义宏
             #undef      取消已定义的宏
             #if         如果给定条件为真,则编译下面代码
             #ifdef      如果宏已经定义,则编译下面代码
             #ifndef     如果宏没有定义,则编译下面代码
             #elif       如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
             #endif      结束一个#if……#else条件编译块
             #error      停止编译并显示错误信息

    四、指针

    1 10个指针的数组 int *p[10];

         int (*p)[10]p是一个指针。它的类型是:指向int x[10]这样的一维数组的指针。

        指向函数的指针,函数有一个整型参数并返回一个整数型 int (*p)(int);

    一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数 int (*p[10])(int);

    2、char a[9]="abcdefg";     char *p="abcdefg";

    其它区别:1.指针保存数据的地址,如p保存的是常量字符串“abcdefg”地址,对p内容的修改是非法的 ;数组保存的是数据,对数组的内容可以直接修改。

    五、限定符的用法

    1const  

     1)作用:a.告知参数的应用目的

                     b.使优化器产生紧凑的代码

                     c.保护不希望被改变的参数:防止参数意外改变

       2)例子:a.  const int a;  a是一整型常量

                      b. int const a;  同上

                     c. const int *a; 指针a指向的内容不可变

                     d. int * const a;指针a指向的内容可变,但指针不可变

                     e. int const * a const; 都不可变

    面试的问题:

         a.一个参数既可以是const又是volatile吗?

         b.一个指针可以是volatile吗?

        答:a.可以,例子:只读的状态寄存器,它是volatile因为可能被意想不到的改变,是const因为不希望程序试图去改变它。

               b.可以。一个例子是中断服务子程序修改一个指向一个buffer的指针时。

    此类考题记住volatile型变量可能随时改变即可。

    2restrict

    restrict关键字允许编译器优化某部分代码以更好地支持计算。它只能用于指针,表明该指针是访问该对象唯一且初始的方式。

    int ar[10];

    int * restrict restar= (int *) malloc(10 * sizeof(int));

     int * par= ar;

    for (n=0; n<10; n++) {

    par[n]+=5;

    restar[n] +=5;

    ar[n] *=2;

    par[n] +=3;

    restar[n] +=3;

     }

    restar是访问它所指向的数据块的唯一且初始的方式,编译器可以把涉及restar的两条语句替换成下面的语句,效果相同:

    restar[n] +=8;/*可以进行替换*/

    3、register

    register关键字请求让编译器将变量a直接放入寄存器里面,以提高读取速度,因为register变量可能不存放在内存中,C语言中register关键字修饰的变量不可以被取地址,但是c++中进行了优化。

    六、精度和优先级

    1类型不同的操作数运算,精度向低级自动转换。无符号+有符号=无符号

    2.int a=12,则执行完语句 a+=a-=a*a后,a的值是-264.

    所有的赋值符(包括复合赋值)都具有右结合性,就是在表达式中最右边的操作最先执行,然后从右到左依次执行。

    3c中函数参数默认是从右向左压栈的,printf计算参数时也是

         int arr[]={6,7,8,9,10};     int *ptr=arr;    *(ptr++)+=123;

         printf("%d,%d ",*ptr,*(++ptr));结果为8

      printf内的参数从右向左运算。

    4位运算要考虑机器字长,算术运算符优先级高于移位运算符

    unsigned char = 0xA5;   unsigned char  b = ~a>>4+1; b250.   

    5三个float:a,b,c .问值 (a+b)+c==(b+a)+c (a+b)+c==(a+c)+b

    不一定相等,float存在大数淹没小数的情况,如 
    float   a=100000000000,b=-100000000000,c=0.00000000001; 
    cout < <a+b+c < <endl; 
    cout < <a+c+b < <endl; 
    结果是1e-0110 
    尽量把数量级相近的数先相加

     

    七、大小端问题

      大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。armpowerpc

      小端模式:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。intelx86

    大小端测试程序1

           int checkSystem( )

           {union check

              {int i;    char ch;

              }c;       c.i=1;        return (c.ch==1);

           }

     测试大小端的程序2

     

    在使用little endian的系统中 这些函数会把字节序进行转换

     define HTONS(n) ((((u16_t)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))

    ltons unsigned short类型从主机序转换到网络序

    htonl unsigned long类型从主机序转换到网络序

    ntohs unsigned short类型从网络序转换到主机序

    ntohl unsigned long类型从网络序转换到主机序

    在使用big endian类型的系统中 这些函数会定义成空宏

    利用linux中自带的宏进行判断:

    #if __BYTE_ORDER == __LITTLE_ENDIAN 
    // 小头字节序 
    #elif __BYTE_ORDER == __BIG_ENDIAN 
    // 大字节序

    八、内存

    1、申请内存的函数

    void *calloc ( size_t num_elements, size_t element_size );

    void *realloc (void *ptr, size_t new_size );

    realloc函数用于修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。当起始空间的地址为空,即*ptr = NULL,则同malloc。callocmalloc相比:calloc分配的内存被初始化为0calloc两个参数:元素个数,元素大小

    2、内存分布

    BSS段:未初始化的全局变量和静态变量;数据段:初始化的全局变量和静态变量;代码段(或文本段):可执行文件的指令;局部变量运行时创建并存储于栈,函数结束即释放;静态变量和全局变量则在程序结束后释放;可执行文件中包含BSS段所需要的大小,但不是BSS段,堆栈等在程序运行时创建

    九、中断

    1 找出下面一段ISR的问题。
          __interrupt double compute_area (double radius)
      {
          double area = PI * radius * radius;
          printf(" Area = %f", area);
          return area;
      }
     1ISR不能传递参数。
     2ISR不能有返回值。
     3ISR应该短且有效率,在ISR中做浮点运算不明智。

    4ISR中不应该有重入和性能上的问题,因此不应该使用pintf()函数。

    不可重入函数不可以在它还没有返回就再次被调用。例如printfmallocfree等都是不可重入函数。因为中断可能在任何时候发生,例如在printf执行过程中,因此不能在中断处理函数里调用printf,否则printf将会被重入。 函数不可重入大多数是因为在函数中引用了全局变量。例如,printf会引用全局变量stdoutmallocfree会引用全局的内存分配表。

    十、链表

    一个链表不知道头结点,有一个指针指向其中一个结点,请问如何删除这个指针指向的结点:将这个节点复制成下一个节点的值,然后删除下一个节点

    typedef struct LinkList {

             int Element;

             LinkList * next;

    }LinkList;

    初始化:

    linklist *  List_init(){

        linklist *HeadNode= (linklist*)malloc(sizeof(linklist));

        if(HeadNode == NULL) {

            printf("空间缓存不足");

            return HeadNode;

        }

        HeadNode->Element= 0;

        HeadNode->next= NULL;

    Return HeadNode;

    }

    创建链表:

    void CreatList(linklist *HeadNode,int *InData,int DataNum)

    {

        int i = 0;

        linklist *CurrentNode = (linklist*) HeadNode;

        for(i = 0;i<DataNum;i++)

        {

            CurrentNode->Element = InData[i];

            if(i< DataNum-1)// 由于每次赋值后需要新建结点,为了保证没有多余的废结点

            {

                CurrentNode->next =(linklist *)malloc(sizeof(linklist));

                CurrentNode= CurrentNode->next;

            }

        }

        CurrentNode->next= NULL;

    }

    插入节点:

    bool InsertList(linklist *HeadNode,int LocateIndex,int InData){

        int i=1;// 由于起始结点HeadNode是头结点,所以计数从1开始

        linklist *CurrentNode= (linklist *) HeadNode;

        //CurrentNode指向待插入位置的前一个结点(index -1

        while(CurrentNode&& i<LocateIndex-1){

            CurrentNode= CurrentNode->next;

            i++;

        }

        linklist *NodeToInsert=(linklist*)malloc(sizeof(linklist));

        if(NodeToInsert == NULL){

            printf("空间缓存不足");

            return ERROR;

        }

        NodeToInsert->Element= InData;

        NodeToInsert->next = CurrentNode->next;

        CurrentNode->next = NodeToInsert;

        return OK;

    }

    具体参考:https://blog.csdn.net/u012531536/article/details/80170893

    十一、内联函数

    内联函数(inline

    带参数的宏

    编译(汇编)时展开 

    预编译时替换

    严格的参数类型检查   

    简单的替换

    函数体不能太大,不能包含大循环和递归

    没要求

    当编译器发现某段代码在调用一个内联函数时,它不是去调用该函数,而是将该函数的代码,整段插入到当前位置。这样做的好处是省去了调用的过程,加快程序运行速度。内联函数适用于函数体较小且频繁使用的函数,调用时进行代码的复制,无需跳转、入栈等操作,以空间换时间而且因为函数有严格的参数类型检查,比宏要安全;内联函数在编译时不单独产生代码  

  • 相关阅读:
    C#中的json操作
    Webdriver 怎么操作 scrollbar 下拉框
    jQuery 选择器
    BUYING FEED (第三届省赛)
    AMAZING AUCTION (第三届省赛)
    聪明的“KK” (第三届省赛)
    网络的可靠性 (第三届省赛)
    如何通俗理解——>集群、负载均衡、分布式
    常用的shell命令
    javascript实现原生ajax
  • 原文地址:https://www.cnblogs.com/xiaomayi-cyj/p/10552021.html
Copyright © 2011-2022 走看看