C语言面试知识点-part1

本文详细介绍了C语言面试中常见的知识点,包括static的作用、引用与指针的区别、预处理指令的功能、内存对齐的概念与规则,以及堆栈的区别。此外,还探讨了全局变量、局部变量、静态变量的内存分配,以及const和volatile关键字的应用。文章通过实例讲解了中断处理的基本原理,以及在C语言中如何定义和使用中断服务程序。
摘要由CSDN通过智能技术生成

第一部分:基本概念及其它问答题

1. static

static定义的变量与全局变量都会被放在全局区里,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放。(关于内存分配,还有栈区(stack),堆区(heap),文字常量区,程序代码区)

虽然静态变量和全局变量都会存储在全局区,但作用域是有区别的,在此加以区分。

  • 全局变量具有全局作用域。你可以在一个文件中定义一个全局变量,然后在多个文件中访问这个变量。(需要使用extern关键字声明变量。注意“声明“与“定义”的区别。)
  • 静态局部变量具有局部作用域,一般是在函数体内声明及定义,所以作用域局限在函数体内,函数体外不可见。与局部变量的区别在于静态变量只被定义一次。(请不要被“在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。”所迷惑)。事实上受影响的只是通过static int a = 3;这种方式定义的静态局部变量。这条static int a = 3;不会被多次执行。所以一旦a值已经被改变了(你可以随便修改变量值,没有在调用过中维持值不变一说),下次再调用这个函数的时候,a不会被重新初始化为3,而是上一次执行时被保存的值。这主要是由于变量存在于全局区的原因。你想想,全局变量不也是会保存之前的值吗?要不然叫什么全局变量啊。但如果你static int a; a = 3; 那只有static int a 这一行不被执行,a还是会被改回3的。
  • 静态全局变量因为是在函数体外,所以在文件内的函数都是可见的。但在文件外是不可见的。也就是说如果你在一个文件里定义了静态变量,在其它的文件中是不可以访问的。说白了,static和extern是互斥的。static全局变量限定了变量只在文件内起作用,extern则是表明变量作用域可以扩展到其它文件。(没有修饰描述符,默认为extern)
  • 静态全局函数与静态全局变量的道理是一样的。

2. "引用"与"指针"的区别

https://www.cnblogs.com/gxcdream/p/4805612.html

  • C和C++使用指针,并且暴露给程序员,Java和C#也使用指针,但把指针隐藏起来了。
  • 引用和指针是有本质区别的,引用是别名,而指针是地址。因为引用只是对象的别名,所以定义引用的时候,就必须绑定对象,否则就没有意义了。同时引用一旦绑定了对象,就不能再修改到绑定其它对象了。而指针则不用,指针是指向某一地址的变量,是可以修改的。
  • 从内存分配上,指针是一个变量,所以需要分配内存的,而引用只是一个别名,只是指向绑定的对象,所以不需要再分配内存。(标准没有规定引用要不要占用内存,也没有规定引用具体要怎么实现,具体随编译器 http://bbs.csdn.net/topics/320095541)
  • 从编译上看,程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。指针变量在符号表上对应的地址值为指针变量的地址值,而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变指向的对象(指针变量中的值可以改,也就是说虽然符号表不能改,但对于指针变量来说,符号表只是存的指针变量的地址,但这个地址上的值是可以改变的,这样也就改变了指针指向的对象。但引用不用,引用在符号表里就是对象的地址,而这个地址又不能改,所以引用的对象是无法修改的),而引用对象不能改。这是使用指针不安全而使用引用安全的主要原因。从某种意义上来说引用可以被认为是不能改变的指针。
  • 引用的大小是所指向的变量的大小,因为引用只是一个别名而已;指针是指针(地址)本身的大小,32位系统下,一般为4个字节

3. 预处理指令(Preprocessor)

源代码被编译之前,由预处理器(Preprocessor)对源代码进行的处理。这个过程并不对程序的源代码进行解析,但它把源代码分割或处理成为特定的符号用来支持宏调用
预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译、布局控制和宏替换4种。
#include (<>用来引用标准库头文件,""常用来引用自定义的头文件。<>编译器只搜索包含标准库头文件的默认 目录,“”首先搜索正在编译的源文件所在的 目录,找不到时再搜索包含标准库头文件的默认 目录.)
#if/#elif/#else/#endif
#ifdef
#define/#undef (在编译前,define的常量会直接替换源代码中的符号。#define的缺点:1. 不支持类型检查;2. 不考虑作用域;3. 符号名不能限制在一个命名 空间中;) 
定义宏
#define Print(Var) count<<(Var)<<endl
用宏名中的参数带入语句中的参数, 宏后面没有;号, Print(Var)中的Print和(之间不能有空格,否则(就会被解释为置换字符串的一部分; 所有的情况下都可以使用内联函数来代替宏,这样可以增强类型的检查。 注:给替换变量加引号)
#ifndef (防止重复引入某些头文件)
#line (重新定义当前行号或文件名)
#error(输出编译错误消息,停止编译)

标准的预处理器宏
LINE 当前源文件中的代码行号,十进制整数
FILE  源文件的名称,字符串字面量
DATE  源文件的处理日期,字符串字面量,格式mmm dd yyyy其中mmm是月份如Jan、Feb等 dd是01-31 yyyy是四位的年份
TIME 源文件的编译 时间,也是字符串字面量格式是hh:mm:ss
STDC 这取决于实现方式,如果编译器选项设置为编译标准的C代码,通常就定义它,否则就不定义它
__cplusplus 在编译C++ 程序时,它就定义为199711L

#pragma (设定编译器的状态或者是指示编译器完成一些特定的动作)
#pragma message("") 当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
#pragma code_seg([“section-name”[,“secti

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值