一、基本概念
1.什么是三字母词?
三字母就是用三个字符组成一个新的字符
例如:'??)' 就是 ']' 的意思
三行符在某些缺少一些必须字符集的C环境下可以使用,一般不用
2.为什么需要转义字符?有哪几类转义字符
a.有些表达需要使用特殊的字符
例: printf("hello");
这里的双引号以内的字符串代表要进行格式化输出的内容,所以当要格式化输出一个双引号时时,就要使用转义符了
b.某些无法打印的字符
例: ‘\n’ 表示换行符,它也是一个字符
c,转义符本身也需要转义
例:‘\\’ 表示 '\'
二、数据
1.基本数据类型有哪些?
整型,浮点型、指针,结构体
2.整型字面量、字符常量、字符串常量、常量之间的区别?
整型字面量:1
字符常量:'1'
字符串常量: "1"
常量都由const关键字修饰,在声明时候就需要初始化,放在内存中的常量区
const int a = 1;
3.signed和unsigned修饰符的作用及注意点有哪些?
对于char类型,某些环境下是signed类型,某些环境下是unsigned类型,一般情况下最好定义为unsigned,方便代码的移植
当signed类型和unsigned类型进行运算时,signed类型会自动转换为unsinged类型
浮点型没有unsigned类型
4.对于每一个变量、常量和函数,可以使属于哪些作用域?
- 原型级别的: 在函数原型中
- 语句块级别的:在语句块中
- 文件级别的: 在整个文件中
5.作用域和链接属性的区别?
链接属性是针对同一标识符来说的,主要用于处理在不同文件中多次声明相同的标识符名称后,如何判断这些标识符是否是同一个
三、语句
1.表达式与语句的区别?
“表达式”是由一个或多个操作数以及零个或零个以上的运算符所组成的序列,可以通过计算得到一个值、对象、方法或命名空间等结果。
语句可以是以分号结尾的单行代码。
表达式:x+1(可以得到一个值)
语句:x=x+1;(一系列完整的命令)
四、操作符和表达式
1.直接赋值与复合赋值有什么区别?
在java中,复合赋值会自动把等号右边的操作数的类型转化为左操作数的类型
在c里面,复合赋值的左操作数只求值一次
例如:
a[1 + 2] = a[1 + 2] + 1;//1 + 2计算了两次
a[1 + 2] += 1; //1 + 2计算了一次
2.逗号操作符如何使用?
含有逗号操作符的表达式的值是最后那个表达式的值
例如:
while ( a++, b > 0){}中,循环是否继续的条件是b>0
3.在表达式中,左值和右值的区别是什么?
左值必须是有固定的地址来接受右边传来的值,右值可以使任意的变量,常量
4.哪些常见的操作符的结合性是从右至左的?
- 前缀自增:++
- 前缀自减:--
- 间接访问:*
结合性是指同一操作符的运算次序
优先级是指不同操作符的运算次序
5.优先级和求值顺序是否总会保持一致?
对于 a*b + c*d + e*f
其运算步骤可能是
a*b
c*d
(a*b) + (c*d)
e*f
(a*b) + (c*d) + (e*f)
在这里,只要每个乘法运算在它相邻的加法运算之前执行即可,因为优先级只对相邻的操作符的执行顺序起作用
五、指针
1.NULL指针的作用
NULL指针表示一个指针没有进行任何指向,其值为0,对于暂时不知道指向的指针,初始化为NULL,方便程序的调试
2.指针直接进行加减操作要注意什么?
只有指向同类型的指针才能进行算术运算,指针加减操作一般用在指向同一数组的不同位置的两个指针,对于指向不同类型的指针进行运算,运算结果是未定义的
六、函数
1.通过stdarg宏来实现的可变参数列表有哪些参数是未知的?
参数的个数和每个参数的类型
七、数组
1.在哪些情况下,一维整型数组名表示的不是指向一个整型的指针?
对于取地址符*和sizeof运算符,一维整型数组名返回的是指向一维数组的指针
2.字符数组的初始化要注意哪些?
对于一般数组,指定大小的数组在初始化时候编译器能够进行边界检测,在以后的赋值过程中,如果发生边界溢出,会产生不可预知的效果
对于字符数组,要注意末尾添加’\0’,只有下面两种情况,编译器会自动在末尾添加’\0’
char a[] = {"123"}
char *a = "123";l
char a[3] = {"123"}//编译器会提示边界溢出
3.定义二维数组时,为什么第二个代表数组大小的参数必须指定?
二维数组其实可以看成一个存放一维数组的一维数组,既然定义一维数组的时候都要指定是int 还是float,即数组单位元素的大小,好为每个元素分配空间,以此类推,那么在定义二维元素时,也应当指定存放的一维数组大小
同理,定义二维数组时第一个参数不用指定,和定义一维数组时的大小不用指定,是一个意思
4.二维数组用二维矩阵表示还是用指针数组表示的优缺点?
- 二维矩阵把每个空间都定义好了,统一管理很方便操作,但是由于每行数组的个数不一定一样,这样就有可能造成空间浪费的问题
- 使用指针数组维护起来麻烦一些,要自己设定每行数据结束的标志
第九章 字符串、字符和字节
1.strlen与sizeof的区别?
前者返回的是字符串的有效长度
后者放回的字符串的大小(包括‘\0’)
2.strlen返回的是无符号数,应该注意什么?
比较两个字符串长度大小时不用进行相减,应该直接用关系运算符比较
第十章 结构和联合
1.联合有何优缺点?哪种情况适合用联合?
相对于结构体,如果使用次数多的话,而且又满足内在属性不同同时出现,使用联合可以大大节省空间,例如:
有一个结构体
S{
int type;
float f;
int i;
}
S可以表示一个整型可以刻表示成一个浮点型,我们通过对其type的判断来认定S属于哪种类型
当然,我们可以用int i 和 float f 来达到同样的目的,但这样数据就分散了,不利于管理
第十一章 动态内存分配
1.malloc和calloc、remalloc有什么区别?使用它们的时候要注意什么?
malloc和calloc都是向系统申请一定大小的空间,如果申请失败,则会返回NULL指针,唯一的区别就是后者会把会申请的空间初始化为0
第十二章 高级指针话题
1.指向指针的指针主要有那两个用途?
基本用途是用来指向一个指针
a.当指针a本身地址作为实参传递时,指向指针的指针b作为形参,改变*b的值,就是可以改变a的指向
b.由于指向指针的指针b可以指向一个指针a,指针a可能是指向的单个值或者是一个数组,如果是后者,那么b就可以看成指向的是一个二维数组,如命令行参数char **argv,与直接定义一个指向数组的指针(如int (*p)[3])异曲同工,都可以用下标直接访问,不同的是,这样的二维数组第二维的节点个数不是一致的
2.函数指针主要有哪两个用途?
- 回调机制:调用者传递一个函数指针给被调用者,让被调用的函数在函数体中使用函数指针,回调这一函数
- 转移表:如果一个函数中有一个switch,包含的许多case,这个函数体就太过复杂,新增新的case也不方便,所以可以把case转换成一个个函数指针,放在一个指针数组里面,通过访问数组来实现对于的switch机制
利用typedef简化定义,例如:
typedef bool (*CmpFun)(int i, int i);
进行定义
CmpFun f1;
CmpFun f2;
3.字符串常量返回的是什么,基于这个,可以有哪些应用?
字符串常量返回的是指向字符串第一个字符的地址的指针,同时,编译器会对字符串常量最后一个位置进行‘\0’的补齐,通过这两个性质,可以把字符串常量,看成一个表,可以进行一些查表的动作
4.调用函数的三种方式
如有函数:void f(){}
有一函数指针指向它 void (*p)() = &f;
有如下三种调用方式
- f();
- (*p)();
- p();
函数调用最是被要把函数在内存中的地址传给调用者
第一种和第二种方式一开始会把函数名转化成一个指向该函数的函数指针,然后执行这个内存位置的代码
第三种方式就直接把这个函数指针给调用者,没有执行间接操作
第十四章 预处理器
1.宏是什么?它和函数的区别在哪儿?
宏只是简单的文本替换,所以不一样,和函数最大的区别是它不进行类型检查
2.条件编译中,判断条件为什么要是常量表达式?
因为条件编译时在编译的时候进行条件判断,来达到选择性编译的效果,判断条件必须在编译期间就要已知,这样,只有常量表达式符合要求
3.头文件为什么不能重复包含?
头文件里面经常会有一些定义和声明,除了声明、类和内联函数的定义,其余的定义都不能重复,头文件的重复包含会导致重复定义的产生
4.C语言中如何实现模板机制?
类模板是一种对数据类型进行抽象的,c里面不能实现完完全全的模板,在特定情况下,例如读取数据指定字节的数据,可以利用void指针,对指针类型进行抽象,传递一个地址,我们不关心它指向的类型,只是以这个地址为起点,读取指定字节的数据
第十五章 输入/输出函数
1.流是什么?有什么作用?
流是c函数库为I/O库函数提供的接口,具体表现就是指向FILE类型指针,它隐藏了具体的I/O操作,然所有I/O操作只是简单的从程序移进或移出字节的事情。调用层次如下所示:
流一般是完全缓冲的,有自己的缓冲区
流分为两种,字节流和字符流,对于每种流,C函数库里面都有相应的函数对其进行操作
ANSI C都会至少提供三个标准流,stdin、stdout和stderr,它们都是指向FILE结构的指针
2.用户在控制台的行输入分为格式化输入和非格式化输入,输出也一样
3.c语言可以在建立一个临时文件,当然这个临时文件在不用后需要显示的删除