C语言易错题 and 易混淆知识

Posted -YIN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言易错题 and 易混淆知识相关的知识,希望对你有一定的参考价值。

1. 以下关于指针的说法,正确的是( )

A.int *const p与int const *p等价
B.const int *p与int *const p等价
C.const int *p与int const *p等价
D.int *p[10]与int (*p)[10]等价

A:错误,int* const p中,const修饰指针变量p本身,表示p的指向不能改变, int const *p中,const修饰p指针解引用之后的结果,表示p指向的内容不能改变 因此,不等价

B:错误,同上

C:正确,const都修饰p指针解引用之后的结果,表示p指向的内容不能改变

D:错误,int p[10]定义了一个指针数组,数组中10个元素,每个元素都是int类型的指针 int (*p)[10]定义了一个数组指针,该指针只能指向存储10个整形元素的数组

  
  
  
  
  

2. 由多个源文件组成的C程序,经过编辑、预处理、编译、链接等阶段会生成最终的可执行程序。下面哪个阶段可以发现被调用的函数未定义?( )

 A.预处理
 B.编译
 C.链接
 D.执行


  解析:预处理只会处理#开头的语句,编译阶段只校验语法,链接时才会去找实体,所以是链接时出错的,故选C。

预处理:相当于根据预处理指令组装新的C/C++程序。经过预处理,会产生一个没有头文件(都已经被展开了)、宏定义(都已经替换了),没有条件编译指令(该屏蔽的都屏蔽掉了),没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有所不同。
  
编译:将预处理完的文件逐一进行一系列词法分析、语法分析、语义分析及优化后,产生相应的汇编代码文件。编译是针对单个文件编译的,只校验本文件的语法是否有问题,不负责寻找实体。
  
链接:通过链接器将一个个目标文件(或许还会有库文件)链接在一起生成一个完整的可执行程序。 链接程序的主要工作就是将有关的目标文件彼此相连接,也就是将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。在此过程中会发现被调用的函数未被定义。需要注意的是,链接阶段只会链接调用了的函数/全局变量,如果存在一个不存在实体的声明(函数声明、全局变量的外部声明),但没有被调用,依然是可以正常编译执行的。

  
  
  
  
  

3. test.c文件中包括如下语句:文件中定义的四个变量,哪个变量不是指针类型?( )

#define INT_PTR int*
typedef int*int_ptr;
INT_PTR a,b;
int_ptr c,d;

 A. a
 B. b
 C. c
 D. d

提示:define 和 typedef

  
  
  
  
  

2.分析以下函数的空间复杂度( )

int** fun(int n)
   int ** s = (int **)malloc(n * sizeof(int *));
     while(n–)
     s[n] = (int *)malloc(n * sizeof(int));
   return s;

A.O(n)
B.O(n^2)
C.O( 1 )
D.O(nlogn)


  int** fun(int n) 
    int ** s = (int **)malloc(n * sizeof(int *));     //s[][n]
    while(n--)
      s[n] = (int *)malloc(n * sizeof(int));          //s[1][n]、s[2][n]...
    return s;
  

  
  
  
  

写一个宏,计算结构体中某变量相对于首地址的偏移,并给出说明

考察:offsetof宏的实现

解决方案:StructType是结构体类型名,MemberName是成员名。具体操作方法是:

1、先将0转换为一个结构体类型的指针,相当于某个结构体的首地址是0。此时,每一个成员的偏移量就成了相对0的偏移量,这样就不需要减去首地址了。
2、对该指针用->访问其成员,并取出地址,由于结构体起始地址为0,此时成员偏移量直接相当于对0的偏移量,所以得到的值直接就是对首地址的偏移量。
3、取出该成员的地址,强转成size_t并打印,就求出了这个偏移量。

#define offsetof(StructType, MemberName) (size_t)&(((StructType *)0)->MemberName)



  


  

指针数组与数组指针

指针就是指针,数组就是数组。

快速判断:(通过操作符优先级)

int (*p)[10];

//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。

//这里要注意:[ ]的优先级要高于*号的。所以必须带上括号是其定义为指针类型。


指针数组

 指针数组是 数组;是存放数据元素为指针的数组。

int arr0[10];   //整型数组
char arr1[5];   //字符数组

int* arr2[4];   //指针数组

arr2 是一个数组,有五个元素,每个元素是一个整形指针。

数组指针

  数组指针是 指针;是指向数组地址的指针,即数组首元素地址。

int arr[6][7];   //arr为二维整型数组
int (*p) [7];   //p为数组指针

以上是关于C语言易错题 and 易混淆知识的主要内容,如果未能解决你的问题,请参考以下文章

C语言指针与数组易混淆知识点

C语言:易错题

C和OC的基础语法(易混淆的概念知识)

分析PMP易混淆知识十大点

c++概述--易混淆点记录

c++概述--易混淆点记录