• 《C语言知识点》


    https://wenku.baidu.com/view/5bf31284ba0d4a7302763a8a.html

    1. #define定义的宏和const定义的常量有什么区别?

    1、两者的区别
    (1) 编译器处理方式不同
    #define 宏是在预处理阶段展开。
    const 常量是编译运行阶段使用。
    (2) 类型和安全检查不同
    #define 宏没有类型,不做任何类型检查,仅仅是展开。
    const 常量有具体的类型,在编译阶段会执行类型检查。
    (3) 存储方式不同
    #define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。)
    const定义的变量属于只读变量。是有分配内存的。

      注意:只读变量和常量是有区别的。常量肯定是只读的,例如5, “abc”,等,肯定是只读的,因为程序中根本没有地方存放它的值,当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值,只不过这个值由编译器限定不允许被修改。

       其中:int a[n]。数组的大小n应该是个常量。所以用const int n = 5。这个是不行的。

    例程:

    #define N 2 + 3

    int a = N / 2;

    a是多少?

    int a = 2 + 3 / 2
    因为a为int型,所以不能有小数点
    所以a = 3
      const char *pContent; //*pContent是const, pContent可变
    const (char *) pContent;//pContent是const,*pContent可变
    char* const pContent; //pContent是const,*pContent可变
    const char* const pContent; //pContent和*pContent都是const

     

    2. 给定一个整型变量a,写两段代码,第一个设置a的bit3,第二个清除a的bit2,在以上两个操作中, 要保持其它位不变。

    #define BIT3 (0x1 << 3)
    
    static int a;
    void set_bit3(void)
    {
        a |= BIT3;
    }
    void clear_bit3(void)
    {
        a &= ~BIT3;
    }
    
    最上面的括号一定要加上,不然在clear_bit3中会有问题,~的优先级问题

    3. char str[20]="0123456789";

    int len1=strlen(str);

    int len2=sizeof(str);

    len1和len2分别是什么值?

    len1 = 10; strlen计算字符串长度,碰到就停止计数
    len2 = 20,; sizeof计算的是数组内存长度。所以str[20]改为str[],那么len2 = 11;他会计算包括null这个

    4. 请问int * p 和 char * p分别占几个字节?为什么?

    在32位系统中,都是4个字节。
    因为计算的是指针的长度,至于int和char,指的是指针所指向内存的数据类型。

    5. 下面的代码使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码

    __interrupt double compute_area (double radius)

    {

    double area = PI * radius * radius;

    printf(" Area = %f", area);

    return area;

    }

    1、ISR不应该有返回值;
    2、ISR不应该传递参数;
    3、ISR应该是短而高效的,ISR中的浮点运算是不明智的;
    4、ISR中不应该使用printf()函数,printf是不可重入函数(malloc函数也不能用)。

    为什么ISR不能有返回值和传参?

        因为对于ISR是由硬件触发的,因此没有调用者。   

    为什么ISR不能用printf和malloc函数?

        首先因此这两个函数都是不可重入函数。

        printf --------引用全局变量stdout
        malloc --------全局内存分配表

        而中断是随机发生的,如果先使用printf函数,此时中断来临,最后中断里面又使用了printf,那么此时就会改变全局变量stdout的值,也就是最后输出到屏幕的值不是自己所期望的。

     

    6.关键字static的作用是什么?

    1.修饰全局变量时,改变该变量的文件作用域,在其他文件不可调用。
    2.修饰局部变量时,改变该变量存储方式,该变量在全局数据区分配内存。但是变量的作用域不变。
    3.修饰函数时,改变该函数的文件作用域,其他文件不可调用。

    7.用+、-、++、--实现a/5,a为一整数,如a=10,则返回2,a为21,则返回4。

    int fun(int value)
    {
        int ret, i;
        
        ret = 0;
        
        if(value > 0)
        {
            while(1)
            {
                for(i = 0; i < 5; i++)
                {
                    value--;
                    if(value == 0)
                    {
                        return ret;
                    }
                }
                ret++;
            }
        }
        else if(value == 0)
        {
            ret = 0;
        }
        else
        {
            ret = -1;
        }
        return ret;
    }

    8.可重入函数和不可重入函数

      《可重入函数和不可重入函数》 - 一个不知道干嘛的小萌新 - 博客园 (cnblogs.com)

      在多线程中,尤其要特别主要这个概念。对资源要有保护机制。

        

    9.定义一个标准宏MAX,总是输出最大值

    #define MAX((a),(b))    ((a)>(b))?(a):(b)
    
    注意在使用时,尽量不要传入自增++或自减—表达式,否则将会导致多次运算

    10.关键字extern、static、const、volatile分别是什么含义?

    extern 说明变量是在其他文件中定义的,为了达到不包含头文件也可以使用其他文件中的变量 或者 extern “C” 来完成C 和 C++的相互引用
    
    static 改变变量或函数的作用域或生存周期,当修饰全局变量和函数时,改变其作用域为仅在本文件中,其他文件不可以适用;当修饰局部变量时,扩展其生存周期至本程序结束,并且只被初始化一次。
    
    const 改变变量的读写权限至只读
    
    volatile 告诉编译器该变量随时有可能会变化,不要试图在编译的过程中对齐优化;同时在程序运行的过程中,每一次的访问都应该实际的从主存或寄存器中去读。一般用在多线程或中断处理程序中。

    11.要求设置一绝对地址为0x67a9的整型变量的值为0xaa66

    访问一绝对地址把一个整型数强制转换成一个指针。
    
    int *ptr;
    ptr =(int *)0x67a9;
    *ptr= 0xaa66;

    12.下面的代码输出是什么,为什么?

    void func(void)

    {

    unsigned int a = 6;

    int b = -20;

    (a+b > 6)?puts(">6"):puts("<= 6");

    }

    输出>6
    C中运算有规定,如果整型变量间进行数据运算,只要有一个变量是无符号的,结果就按无符号数据

    13.以下两行代码那个实现方式更好?为什么?

    #define dPS struct s *

    typedef struct s * tPS;

    第二种。
        #define 只是简单的在预处理阶段将字符串进行展开
        而typedef则是定义了一个别名
    
     举例:
        dPS c,d;
        实际展开后成为 int *c,d   表示定义了一个整形指针c 和 整形变量 d
    
        tPS c,d
        而 tPS则是一个整体,他代表的就是int *这个类型,所以定义的是两个整形指针c和d

    14.写一个中断服务需要注意哪些?如果中断产生之后要做比较多的事情你是怎么做的?

    1. 中断服务内的执行过程尽量短,并且不去操作硬件资源
    2. 中断服务函数没有传参和返回值
    3. 中断服务函数内的程序应该是可重入的,不能使用printf
    4. 中断服务函数内不应做浮点运算这一类的复杂运算。
    5. 中断服务函数内尽量不要使用锁(互斥锁和自选锁)
    
    当需要做较多的事情时:
        可以中断的发生和事情的处理拆分开来,中断服务程序内只做状态的修改,然后从其他程序中去对相应的状态做不同的处理。
        使用 消息  或 volatile 声明的变量来做状态的传递

     15.堆和栈的区别?

    1.申请方式、栈的空间由操作系统自动分配以及释放。堆上的空间需要手动分配和释放(malloc以及amalloc等的区别?)
    2.申请大小。堆的可用空间比较大,栈的可用空间比较小,一般是2M。
    3.申请效率。栈的申请速度比较慢,堆的申请速度比较快。

    16. 为什么栈的空间不连续 ?

     17.死循环的几种方式

    1.
    while(1)
    {
            ;
    }
    
    2.
    for(; ;)
    {
           ;
    }
    
    3
    LOOP:
    ......
    goto LOOP;
    
    4.
    do
    {
        ;
    }while(1);

    18.左值和右值

    左值可写,右值可读。通常,左值可以作为右值,但是右值不一定是左值。

      左值可能是变量,变量又可以作为右值。但是右值可能是常量,常量不能作为左值。

    19.数组名和指针的区别?

    1.指针是一个变量,而数组名不是。数组名是数组的首地址,即它本身就是一个地址。
    2.假设a是一个数组名,而p是一个指针,当你使用 a 和 &a 时,得到值是一样的,都是数组的起始地址。而使用 p 和 &p 时,得到的值是不一样的, p 表示指针 p 所指向的地址,而 &p 表示 p 这个变量的地址。
    3.对数组的引用,如a[i],或*(a+1),需要访存一次;而对指针的引用,如*(p+1),需要访存两次。
    如果理解了第二条的解释,这个应该就不难理解。因为a被认为是常数,所以取*(a+1)的值只需将a所表示的常数加1,然后从得到的地址里访存取一次即可。而对于指针,需要先从&p这个地址里把p的值取出来,然后加1,再从得到的地址里访存取一次,一共需要两次访存。

     20.指针函数,函数的参数为int,返回值为字符指针

    char *((*p)(int))

      以上只是一个函数声明。所以有用到函数指针的概念。

    21.typedef和define有什么区别

    typedef定义指针的别名时,别名可以连续定义两个指针变量。define定义指针的别名是,使用这个别名连续定义两个指针变量会报错。

    22.数组下标可以用负数吗?

    23.不能用sizeof函数,如何判断操作系统是16位还是32位?

    方法1:
    16位系统:
    int i = 65536;
    cout << i; // 输出0;//装不下,最高位溢出,剩下16位的当然是0;
    int i = 65535;
    cout << i; // 输出-1;//-1的补码是65535
    
    32位系统:
    int i = 65536;
    cout << i; // 输出65536;
    int i = 65535;
    cout << i; // 输出65535;
    
    方法2:
    int a = ~0;//按位取反运算,结果为(11111111111111111111111111111111)
    if( a>65536 )
    {
        cout<<"32 bit"<<endl;
    }
    else
    {
        cout<<"16 bit"<<endl;
    }

    24.什么是4字节对齐?为什么需要对齐?

        字节对齐是为了提高存取效率,并且一般是偶个字节对齐(2 4 6 8……),因为总线的位数都是偶数的(8  32  64……),并且每个周期的周期都是从偶地址开始访问的,若不是没有偶字节对齐,在某些情况(比如若某变量的内存空间为0x33 ~ 0x36)下访问一块内存将会多耗费一个周期。

      4字节对齐就是32位。也就是常规的32位总线。对应我CPU每次去访问内存最大可以一次性访问32位。

      比如定义一个char a[1] = 'a';这个正常只需要8位的存储,如果4字节对齐,就变成32位存储。

      这个时候printf("%c",a[0]);和printf("%d",a[0]);就会出现前者是取了a[0]的前8位,后者是取了a[0]的32位。

    25.怎么计算结构体所占内存?

    26.什么是野指针?如何避免?

    27.sizeof和strlen的区别?

    sizeof是运算符,在程序编译时就已经确定了;
    strlen是函数,程序运行时才能计算。

    29.Int a[5] = {1,2,3,4,5}  sizeof(a) = ?

    20

     memcpy

     

     

  • 相关阅读:
    git操作
    计算天数
    web小结~2019.3.24
    数据统计值的计算+PYTHON
    python~序列类型及操作
    一个日期加上若干天后是什么日期
    完数与盈数
    分段函数
    求最大最小
    D进制的A+B
  • 原文地址:https://www.cnblogs.com/zhuangquan/p/14133449.html
Copyright © 2020-2023  润新知