C语言和数据结构与算法(99)

2023-05-16

1 预处理和关键字(22道)

1.1 宏定义是在编译的哪个阶段处理的?

答案:在编译的预处理阶段,被处理的。

编译预处理包括:宏替换、文件包含、条件编译、其他预处理指令。

1.2  写一个“标准”宏定义MIN,这个宏定义有两个参数,返回较小的一个。

#define MIN(A,B) ( (A) <= (B) ? (A) : (B) )

1.3   已知道数组table,用宏求数组元素个数

#define COUNT(table) (sizeof(table) / sizeof(table[0]))

注意sizeof(table)可以得到数组的长度,sizeof(table[0])获取数组元素的长度

1.4 带参宏和函数的区别

(1) 带参宏只是在编译预处理阶段进行简单的字符替换,而函数则在运行时进行调用和返回。

(2) 宏替换不占用运行时间,只占用编译时间,而函数调用则占用运行时间(分配单元,保留现场,值传递,返回)。

(3) 带参宏在处理的时候不分配内存;而函数调用会分配临时内存。

(4) 宏不存在类型问题,宏名无类型,它的参数也是无类型的;而函数中的实参和形参都要有类型定义,二者的类型要求一致 。

(5) 而使用宏定义次数变多时,宏替换后源程序会变大,而函数调用则不会。

1.5  内联函数的优缺点和适用场景是什么?

    (1) 优点:内联函数与宏定义一样会在编译时展开,省去了函数调用的开销,同时又能做类型检查。

    (2) 缺点:它会使程序的代码量增大,消耗更多的内存空间。

    适用场景:内联函数适用于函数体内代码简单的小函数,对于复杂的函数,即使声明为内联函数,也不一定会被编译器内联。

inline int add(int a.int b)

{

    return a + b;

}

1.6 关键字volatile的作用是什么?给出三个不同的例子

    (1)作用:告诉编译器不要去优化这个变量的值,因为这个变量可能会被意想不到的改变。

    精确的说就是,优化器是在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

例子1 嵌入式系统中,使用vo1ati1e修饰的寄存器,以确保其值

不能被优化或缓存,例如:

volatile int *led_reg = (int *)0x555555; //指向0x555555地址的寄存器

*led_reg = 0x01;//点亮第一个LED灯

例子2   多线程应用中被几个任务共享的变量,(防止死锁)

在多线程或者异步环境中,使用volatile修饰的变量,以确保其在不同线程或者任务之间同步,例如:在下面的例子中,如果不使用volatile修饰count变量,则可能会出现多个线程中对cout变量值相互独立的情况,使用volatile关键字可以避免这种情况的发生。

volatile int counter = 0;

void increment()

{

    while(true)

    {

        counter++;

    }

}

例子3  在并行计算或通信中,使用volat1e修饰的变圣,以确保其能够被共享,

例如:

volatile int  input_data[1024];//共享的输入缓冲区



int fetch_input_data()

{

    //从设备中读取数据并存储到input_data变量中

    ...

}



1.7   如何使用C语言实现读写寄存器变量

#define rBANKCON0 ( *(volatile unsigned long *)0x48000004 )
rBANKCON0 = 0x12;

由于是寄存器地址,所以需要先将类型进行强制转换为 volatile unsigned long *,然后再通过*取值,就可以对寄存器进行读写操作了。

1.8  下面代码能不能编译通过?为什么?

#define c 3

c++;

答案:不能,因为宏定义只是简单的字符替换,所以c++会被替换为3++,而3++是错误的。


 

1.9  "在C语言中,凡是以#开头的都是预处理指令,同时预处理命令都是以#开头的",这句话对不对?

答案:不对,#include <stdio.h>中的#include不是预处理命令,而是预处理指令。

1.10  预处理器标识#error的作用是什么?

答案:#error用于在预处理阶段产生一个错误信息,这个错误信息将被编译器显示出来,然后终止编译过程。

    当程序比较大的时候,往往有些定义是在外部指定的(如makefile),或是在系统头文件中指定的,当你不太确定当前是否定义了xxx时,可写如下的预处理代码:

例子1

#ifdef xxx

#error "xxx has been defined"

#else

...

#endif

这样,如果xxx已经被定义,编译器将会报错,否则,就会执行后面的代码。

例子2 查看编译器版本是否符合要求

#if __STDC_VERSION__ < 199901L

    #error "C99模式编译器才能编译此程序"

#endif


 

1.11  用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)。

#define SECONDS_PER_YER (60 * 60 * 24 * 365)UL


constexpr unsigned long SECONDS_PER_YEAR = (60 * 60 * 24 * 365UL);//对于C++需要将UL放入括号内,否则会编译不过

注意:UL表示无符号长整型,这里用UL是为了防止溢出。


 

1.12 关键字static的作用是什么?

    (1) static修饰局部变量:①改变了其存储位置,储存在静态区;②同时改变了其生命周期,为整个源程序

    因此它只被初始化一次,若没显示初始化则自动化初始化为0。

    (2) 修饰全局变量:改变了其作用域,只可以被为文件所用的函数访问。

    (3) static修饰函数:改变了其作用域,只可以在这一文件内的其他函数调用


 

1.13 下面是关键字const的使用示例,请说明它们的作用:

const int a = 10; //a是一个整型常量

int const a;//a是一个整型常量



const int *a;//a是一个指向整型常量的指针变量

int *const a;//a是一个指向整型变量的指针常量

int const * const a = &b;//a是一个指向整型常量的指针常量



char *strcpy(char *strDest,const char *strSrc);//参数在函数内部不会被修改

const int strcmp(char *source,char *dest);//函数返回值不会被修改

const放在*的左边是修饰指向的对象,放在*的右边是修饰指针本身。


 

1.14 一个参数既可以是const还可以是volatile吗?解释为什么,一个指针可以是volatile吗?解释为什么?,下面的函数有什么问题?

一个参数既可以是const还可以是volatile吗?解释为什么?(性质不互相影响)

答案:可以,因为const和volatile修饰的是两个不同的概念,一个是只读,一个是易变,两者之间没有冲突。

一个指针可以是volatile吗?(性质相同)

答案:可以,指针是一个变量,volatile修饰的是变量,所以指针也可以是volatile。

下面的函数有什么问题?

int square(volatile int *ptr)

{

    return *ptr * *ptr;

}

这个函数的目的是用来返回指针*ptr指向的值的平方,但是由于*ptr指向一个volatile类型的参数,

编译器会产生类似下面的代码:

int square(volatile int *ptr)

{

    int a,b;

    a = *ptr;

    b = *ptr;

    return a * b;

}

由于*ptr指向的值可能会被意想不到的改变,所以a和b的值可能不一样,所以这个函数是有问题的。正确代码如下:

long square(volatile int *ptr)

{

    int a;

    a = *ptr;

    return a * a;

}


1.15  关键字typedef在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理做类似的事情,例如思考下面的例子:

#define dPS struct s *

typedef struct s * tPS p;//(顺序、分号、#号)

以上两种情况的意图都是定义dPS和tPS作为一个指向结构体s的指针,哪种方法更好?为什么?

    typedef更好,因为这种方式更直接,更易读,更具有可维护性,#define的方式更容易出现副作用,看例子1,在下面代码中,使用了#define和typedef定义了两个指向结构体s的指针类型p1和p2,其中p2没有使用#define,如果使用#define宏定义的方式,预处理会将所有的dPS替换为struct s *,这样就会导致p1和p2的大小不一致。而如果采用typedef的方式直接定义指针类型,则不会出现这个问题。

    因此,为了避免使用#define宏定义和typedef组合定义时可能导致的问题,建议直接使用typedef定义指针类型。

例子1

#define dPS struct s *

typedef struct s * tPS p;

typedef dPS p2;

int main()
{

    p1 myp1;

    p2 myp2;

    printf("sizeof(p1) = %d\n,sizeof(p2) = %d\n",(int)sizeof(p1),(int)sizeof(p2));

    return 0;

}

例子2

dPS p1,p2;

tPS p3,p4;

    第一行代码扩展为struct s *p1,p2;即定义p1为一个指向结构体的指针,p2为一个实际的结构体,这也许是你不想要的。第二行代码正确的定义了p3和p4两个指针。

1.16  关键字sizeof的作用是什么?函数strlen()呢?

    (1)sizeof的作用是用来计算变量,数据类型所占用的字节数。sizeof(数组名)得到数组

    所占用的字节数,sizeof(字符串指针名)得到指针所占字节数。

    (2)strlen()函数的作用是计算字符串的长度,不包括字符串结束符'\0'。strlen(字符数组名)得到字符串所占字节数,strlen(字符串指针名)得到字符串所占字节数。

1.17 关键字extern的作用是什么?

答案:用于跨文件引用全局变量,即在本文件中引用一个已经在其他文件中定义的全局变量。

    解析:

    (1)注意引用时不能初始化,如extern var = 0;是错误的。

    (2)另外,函数默认是extern类型的,表明是整个程序(工程)可见的,加不加都一样。

1.18 extern "C"的作用是什么?

    答案:

    (1) 在C++代码中调用C函数。用法:extern "C" void func();例子如下:

    (2) 在C代码中调用C++函数。用法:extern "C" void func();例子如下:

    注意:

    extern "C"只能用于C++文件中,不能用于C文件中。

例子

extern "C"

{

   //C函数库文件声明/函数声明。

}

1.19  关键字auto的作用是什么?

    答案:用来定义自动局部变量,自动局部变量在进入声明变量的语句块时被建立,

    在退出该语句块时被销毁,仅在语句块内部使用。

    解析:

        其实普通局部变量就是自动局部变量,只是省略了auto关键字。


 

1.20  关键字register的作用是什么?其使用的时候需要注意什么?

    (1)作用:编译器会将register修饰的变量尽可能的存放在CPU的寄存器中,以加快其读取速度,

    一般用于频繁使用的变量。

    (2)注意:register变量可能不存放在内存中,所以不能用&取该变量的地址;只有在局部变量和形参

    可以作为register变量,寄存器数量有限,不能定义过多的register变量。


 

1.21  C语言编译过程中,关键字volatile和extern分别在哪一个阶段起作用?

    答案:volatile在编译阶段起作用,extern在链接阶段起作用。

    解析:

        C语言编译过程:预处理->编译->汇编->链接

                                           (volatile)     (extern)


 

1.22  关键字const和#define的区别是什么?

    (1)异:const有数据类型,编译器可以做静态类型检查;

               #define没有数据类型,可能会导致类型出错。

    (2)同:两者都可以定义常数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言和数据结构与算法(99) 的相关文章

  • 白嫖党最爱!javasocket服务端向客户端发消息

    一 公务员都不要35岁以上的 xff0c 何况大公司 这让很多人感到惶恐 xff0c 现在职场上有一种现象 xff1a 很多用人单位会在招聘信息上明确标注 xff0c 年龄需在35岁以下 为什么有经验 有人脉的职场中年人会如此遭 嫌弃 呢
  • Mybatis源码解析:21道Java基础面试题及答案

    10 HashMap和HashTable的区别 答案 xff1a Hashtable和HashMap类有三个重要的不同之处 1 第一个不同主要是历史原因 Hashtable是基于陈旧的Dictionary类的 xff0c HashMap是J
  • Mybatis源码解析:Java泛型详解

    注意 xff1a 泛型的类型参数只能是类类型 xff0c 不能是基本属性类型 xff1b 不能对确切的泛型类型使用instanceof操作 如下面的操作是非法的 xff0c 编译时会出错 if ex num instanceof Gener
  • MySQL数据库优化:Java程序员秋招三面蚂蚁金服

    自我介绍 JVM如何加载一个类的过程 xff0c 双亲委派模型中有哪些方法 xff1f HashMap如何实现的 xff1f HashMap和Concurrent HashMap区别 xff0c Concurrent HashMap 线程安
  • 【shell】shell脚本模板

    参考 xff1a cShell脚本模板 运维 64 小兵的博客 CSDN博客 bin bash set e 打开异常退出功能 set x 打开Debug功能 定义变量 source etc profile 避免用contab ansible
  • ROS中自定义头文件、源文件和可执行文件调用

    编写头文件 头文件创建在功能包 include 功能包名路径下 xff0c 示例内容如下 xff1a ifndef haha define haha namespace haha ns class Person public void ru
  • STM32/51单片机进阶技一 裸机编程(多任务处理编程思想与代码风格)

    文章目录 系列文章目录前言一 裸机编程是什么 xff1f 二 使用步骤 1 main c主函数处理2 中断函数处理总结 前言 在单片机编程当中 xff0c 我们难免会用单片机处理1个 xff0c 2个简单的任务 xff0c 但是当任务数量超
  • 用JavaScript写的猜数字游戏

    先输出游戏目的 xff0c 用Math Random找到随机数 xff0c 其取值在0 1之间 xff0c 故乘100 直到输入的数字和随机数a相等时才跳出循环 否则 xff0c 判断输入值如果大于随机数 xff0c 则输出你猜的数偏大哦
  • 使用JS脚本打开多个网页的方法

    01 问题 如每天都需要刷新重复的网页或许数据 有什么解决办法吗 02 解决方案 大家可以移步是你的Sakura的 打开多个相关联的网页 js脚本打开网页方法 03 代码 span class token tag span class to
  • 安装 rotors-gazebo 时 melodic版本遇到的问题

    针对找不到qt gui的问题 Could not find a package configuration file provided by 34 qt gui 34 with any of the following names qt g
  • Promethus(普罗米修斯)安装与配置

    1 普罗米修斯概述 Prometheus 是由go语言 golang 开发 是一套开源的监控 amp 报警 amp 时间序列数 据库的组合 适合监控docker容器 Prometheus是最初在SoundCloud上构建的开源系统监视和警报
  • 对C++中的继承分析和总结

    文章目录 一 继承的概念二 继承的定义1 继承的定义格式2 继承方式和访问限定符 三 基类和派生类的赋值规则1 派生类赋值给基类2 基类赋值给派生类 四 继承中的重定义 隐藏 五 派生类中的默认成员函数1 不写派生类中的默认成员函数2 写派
  • Linux -- 查看进程 top命令 详解

    我们上篇介绍了 xff0c Linux 中的进程等概念 xff0c 那么 xff0c 在Linux 中如何查看进程呢 xff1f xff1f 我们常用到的有两个命令 xff0c PS 和 top 两个命令 xff0c 今天先来介绍下 top
  • 24届春招百度暑假实习笔试第二题

    题干 解答 该题目在解决的时候 xff0c 需要发现就是对于相同的字符我们应该放在一起 xff0c 这样在进行修改的时候 xff0c 对其他字符的影响才会小 然后连续相同字符个数 和 组成的回文子串数目 它们的通解为 an 61 n 2 4
  • ROS学习(八)launch启动文件的使用方法

    前言 使用命令行输入代码需要不断打开终端比较繁琐 xff0c 而且容易输入错误 xff0c 那么有没有什么方法可以快速启动所需节点呢 xff1f 一 launch文件介绍 Launch文件 xff1a 通过XML文件实现多节点的配置和启动
  • 【git】git lfs

    目录 原理 使用方法 报错记录 certificate signed by unknown authority 原理 项目中的大文件会很占空间 git lfs large file storage 将大文件替换为小指针 当真正需要到这些大文
  • gdb调试应用程序记录

    gdb 调试说明 xff1a 判断程序是否为debug版本 xff1a 方法一 xff1a 命令 xff1a gdb a out 注 xff1a 这里的命令是指在Linux终端下面输入的命令 非debug版本 xff0c 会提示 xff1a
  • 3D打印机硬件驱动-马林固件最新版本2.0.X中文注释(3)marlin 2.0.9.2 截至发稿时间2021年12月16日

    Marlin 3D Printer Firmware 头描述详见其他两个文件头描述 Copyright c 2020 MarlinFirmware https github com MarlinFirmware Marlin Based o

随机推荐

  • 字符串结尾‘\0‘

    C语言中字符串的结束标志是 39 0 39 C语言中没有专门的字符串变量 xff0c 通常用一个字符数组来存放一个字符串 xff0c 字符串总是以 39 0 39 作为结束符 39 0 39 就是8位的00000000 xff0c 因为字符
  • 蒙德里安的梦想 状压 DP

    定义 状压 DP 是动态规划的一种 xff0c 通过将状态压缩为整数来达到优化转移的目的 例题 xff1a 蒙德里安的梦想 求把 N M 的棋盘分割成若干个 1 2 的长方形 xff0c 有多少种方案 例如当 N 61 2 xff0c M
  • Hadoop 核心三大件

    一 Hadoop Distributed File System xff0c 简称 HDFS xff0c 是一个分布式文件系统 二 YARN架构 三 MapReduce架构概述 MapReduce将计算过程分为两个阶段 xff1a Map和
  • 努力加油——感想帖

    一直很想写一篇自己的心路历程 xff0c 这篇文章于2022 10 28午编写 2020年7月10日在高考地理考卷上给自己的中学生涯画上了句号 走出考场那一刻 xff0c 心里像是有一块沉甸甸的石头被放了下来 xff0c 但好像自己并不是很
  • 小国王——状压DP

    在 n n 的棋盘上放 k 个国王 xff0c 国王可攻击相邻的 8 个格子 xff0c 求使它们无法互相攻击的方案总数 输入格式 共一行 xff0c 包含两个整数 n 和 k 输出格式 共一行 xff0c 表示方案总数 xff0c 若不能
  • 小国王(目标状态优化版)—— 状态压缩DP

    在 n n 的棋盘上放 k 个国王 xff0c 国王可攻击相邻的 8 个格子 xff0c 求使它们无法互相攻击的方案总数 输入格式 共一行 xff0c 包含两个整数 n 和 k 输出格式 共一行 xff0c 表示方案总数 xff0c 若不能
  • 炮兵阵地——状态压缩DP

    司令部的将军们打算在 N MN M 的网格地图上部署他们的炮兵部队 一个 N MN M 的地图由 NN 行 MM 列组成 xff0c 地图的每一格可能是山地 xff08 用 H 表示 xff09 xff0c 也可能是平原 xff08 用 P
  • hadoop项目实战——奥运会数据分析

    大三学期项目 hadoop MapReduce 奥运会数据分析结果 xff1a 有没需要详细实现方法的小伙伴呀 xff1f 可以在评论区评论一下 如果人多 xff0c 那么后续会详细更新实现方法
  • RT-Thread 内核线程切换原理

    1 背景 本文章主要说明 rtthread 内核线程是如何切换的 xff0c 初学者刚从裸机开发接触 RTOS 时难免会有些不适应 xff0c 明白这部分原理之后就会对 RTOS 有更深的理解 在学习内核线程切换原理之前需要有以下基础知识铺
  • 【多线程】C/C++语言中多线程和简单例子

    目录 前言 一 pthread两种状态joinable和unjoinable 二 thread join 方法存在的必要性 三 为什么要多线程 xff1a 问题 xff1a 简单的多线程编程 线程的数据处理 四 实例代码 C 43 43 C
  • 单片机开发之裸机也能 “多任务”?

    单片机开发之裸机也能 多任务 xff1f 1 背景 对于一些简单的单片机项目 xff0c 没必要非得跑RTOS xff0c 因此 xff0c 很多项目都是在 裸奔 指纯循环加上中断的机制 所以 xff0c 开发出一套好用的裸机框架是非常有必
  • vscode如何运行C++程序

    首先说一下vscode是一个支持跨平台的轻量级编辑器 1 安装c c 43 43 编译器 Linux系统一般都自带gcc和g 43 43 xff0c 但对于Windows系统而言就需要安装Mingw w64来获得编译器 步骤如下 xff1a
  • TX2 安装显卡驱动

    1 官网查询驱动版本 官方 GeForce 驱动程序 NVIDIA 这个版本gcc不合适 xff0c 换了下一个 又换了一个版本 xff0c 依旧有gcc版本问题 但查了一些资料 xff0c 对照一些版本 xff0c 觉得可能gcc冲突并不
  • 04 ROS Client-Service-Server实例

    零 Service机制 Client与Server向ROS MASTER注册MASTER根据Client订阅的信息 xff0c 查阅注册表中是否有提供对应Service的ServerClient收到Server的TCP通信地址Client用
  • ROS2教程 02 功能包

    一 检查别人的功能包依赖 当移植别人的功能包到本机时 xff0c 需要在工作空间目录下检查功能包依赖是否健全 rosdepc span class token function install span i from path src ro
  • 从零开始学习无人机 00 硬件配置

    遥控器 型号 乐迪Radiolink AT9S Pro 固件更新 对遥控器固件作更新 乐迪Radiolink AT9S Pro 固件更新 光流传感器 型号 思动智能ThoneFlow 3901U 开发文档 Pmw3901光流传感器PX4开发
  • 树莓派ubuntu镜像备份详细教程

    1 获取镜像 将配置好环境的树莓派sd卡放入读卡器将读卡器插入电脑在Windows操作系统上使用软件win32diskimager获取镜像将镜像保存到Linux操作系统上某个位置 xff0c 例如ubuntu22 04 2 减小镜像体积 安
  • Java开发必须会的技能!kafka集群3个节点挂掉一个

    Maven权威指南 首先 xff0c 本书适合所有Java程序员阅读 由于自动化构建 依赖管理等问题并不只存在于Java世界 xff0c 因此非Java程序员也能够从该书中获益 无论你是从未接触过Maven 还是已经用了Maven很长时间
  • 大厂首发!阿里面试官跟我死磕MySQL,Java岗

    前言 蓦然回首自己做开发已经十年了 xff0c 这十年中我获得了很多 xff0c 技术能力 培训 出国 大公司的经历 xff0c 还有很多很好的朋友 但再仔细一想 xff0c 这十年中我至少浪费了五年时间 xff0c 这五年可以足够让自己成
  • C语言和数据结构与算法(99)

    1 预处理和关键字 22道 1 1 宏定义是在编译的哪个阶段处理的 xff1f 答案 xff1a 在编译的预处理阶段 xff0c 被处理的 编译预处理包括 xff1a 宏替换 文件包含 条件编译 其他预处理指令 1 2 写一个 标准 宏定义