C/C++面试题总结1(包含指针很重要的内容)

1. const常量和宏定义常量的区别

1.const常量具有类型,编译器可以进行安全检查

2.#define宏定义没有数据类型,只是简单的字符串替换,不能进行安全检查

3.const定义的常量只有一份,#define有多份

4.const其保护作用,防止修改变量

2.c/c++的基本数据类型在不同32/64位os下各数据类型字节数

基本类型 32位平台下的字节数 64位平台下的字节数 取值范围
bool 1 1 true(!0);flase(0);
char 1 1 [-128,127]
unsigned char 1 1 [0,255]
short 2 2 [-32768,32767]
unsigned short 2 2 [0,65535]
int 4 4 [-231-1,231]
unsigned int 4 4 [0,2^32-1]
long 4 4/8(一般都是4字节) [-231-1,231],~/[-263-1,263]
unsigned long 4 8 [0,232-1],[0,264-1]
double 8 8
float 4 4
long long 8 8
long double(拓展精度浮点数) 8 8
void * 4 8 32位地址空间/64位地址空间
32和64位只用long类型和指针类型的字节数不同
// 指针类型字节数
// 32位:os寻址空间为32位,所以指针为:32bit = 4 byte
// 64位:os寻址空间为64位,所以指针为:64bit = 8 byte    

3.#define定义的函数

#define DOUBLE(x) x+x
cout<<5*DOUBLE(5);

问输出值为?

5*5+5 = 30

4.c语言的字符数组问题

char arr[] = "str"; // sizeof(arr):4,未指定字符数组长度,字符数组会在字符串末尾自动添加'\0'
char at[3] = "ab"; // sizeof(at):3,指定字符数组长度,要留一个位置给'\0'使用,
// 字符数组的长度,是算上'\0'的

5.函数指针和函数指针数组

5.1 指向函数的指针

void a(){
    cout<<1<<endl;
}
void b(){
    cout<<2<<endl;
}
int main(int argv,char** argc) {
    // 函数类型为void ();
    // 定义一个指向没有参数且无返回值的函数
    // 定义一个指向void ()()类型的函数指针p
    void (*p)();
    // 用函数名a(函数入口地址)给指向此函数的指针赋值 p 指向 a
    p = a;
    // 调用a函数
    (*p)();
    // 用函数名b(函数入口地址)给指向此函数的指针赋值 p 指向 b
    p = b;
    // 调用b函数
    (*p)();
    return 0;
}
// 结果:
// 1 2

5.2 指向函数指针的数组 【重点】

void a(){
    cout<<1<<endl;
}
void b(){
    cout<<2<<endl;
}
int main(int argv,char** argc) {
	// 函数类型为:void ()() - 函数指针类型;
	// p[2]里面存储void ()()类型的函数的指针void (*)() -- 存指针地址
    // 定义两个指向void (*)()类型的数组
    void (*p[2])();
    // 赋值
    p[0] = a;
    p[1] = b;
    // 调用函数
    (*p[0])();
    (*p[1])();
    return 0;
}

5.3 函数指针经典案例 -- 括号拆分法

5.3.1 ( * ( void( * )( ) )0)( ) ;
这是《CTraps and Pitfalls》这本经典的书中的一个例子。没有发狂吧?下面我们就来分 析分析:
第一步:void(*)(),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
第二步:(void(*)())0,这是将 0 强制转换为函数指针类型,0 是一个地址,也就是说一 个函数存在首地址为 0 的一段区域内。
第三步:(*(void(*)())0),这是取 0 地址开始的一段内存里面的内容,其内容就是保存 在首地址为 0 的一段区域内的函数。

第四步:(*(void(*)())0)(),这是函数调用。 // 调用0地址处的函数
5.3.2 void( * signal ( int,void( * )( int ) ) )( int )
第一步:signal ( int,void( * )( int ) ),可以明白signal是一个函数名,它有两个参数一个是int,一个是一个void( * )( int )函数指针,且该函数指针指向的是一个匿名函数,该函数参数为int,返回值类型为void型。

第二步:void( * signal ( int,void( * )( int ) ) )( int ),去掉已分析过的黄色部分,可以明白signal函数的返回类型为函数指针类型void(* )( int ),该返回类型(函数指针)指向的是一个匿名函数,该函数参数为int,返回值类型为void型。

5.4 函数指针的应用:回调函数 【重点】

回调函数就是一个通过函数指针调用的函数如果你把函数的指针(地址)作为参数传递给 另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调⽤用,⽽而是在特定的事件或条件发⽣生时由另外的一方调⽤用的,用于对该事件或条件进行响应。

回调函数的例子:

#include <iostream>
using namespace std;
// 使用回调函数

// 当输入数据是'$'时候,计算1+...+n的和
// 该函数指针类型为:int (*)(char,int);
// 这个函数是我们写好的默认是系统的,供其他函数回调的
/**
 * 求和函数
 * @param ch
 * @param n
 * @return
*/
bool sum(const char ch,const int n){
 int t = 0;
 if(ch == '$') {
     for (int i = 0; i < n; ++i) {
         t += i;
     }
     cout << "1+...+n = " << t << endl;
     return true;
 }
 return false;
}
// 函数指针做函数的参数 print是回调函数
/**
 * 求1+...+n的函数,回调sum函数求和
 * @param message:输入信号有误的信息
 * @param ch:输入信号 '$':求和;其他信号:什么也不干
 * @param n:求1+..+n的尾数
 * @param p:回调函数的函数指针
*/
void print(char message[],const char ch,const int n,bool (*p)(const char ch,const int n)){
 bool sign = (*p)(ch,n);
 if (!sign){
     cout<<message<<"is "<<ch<<endl;
 }
}
int main(int argv,char** argc) {
 print("input sign is not $,",'$',10,sum);
 return 0;
}

5.4 函数指针数组应用 【重用表 -- 一般用在汇编语言orC语言写底层时候】

把写好的函数的名字放到一个执行该类型函数的表中,供其他函数查表调用

void producer(){
 cout<<"producer"<<endl;
}
void consumer(){
 cout<<"consumer"<<endl;
}
void consumer1(){
 cout<<"consumer1"<<endl;
}
// arr中存放两个 void (*)()类型的函数指针(函数地址)
void (*arr[3])() = {producer,consumer,consumer1};
int main(int argv,char** argc) {
 int n;
 while (true){
     cout<<"请输入想要调用的函数:";
     cin >>n;
     switch (n) {
         case 0:
             // arr[0]中存储的是函数地址,(*函数地址)():执行函数的意思
             (*arr[0])();
             break;
         case 1:
             (*arr[1])();
             break;
         case 2:
             (*arr[2])();
             break;
         default:
             cout<<"operation is error"<<endl;
             break;
     }
 }
 return 0;
}

6.指向二维数组的指针

6.1 使用一级指针访问二维数组

// a[2][3]:
// 就是2个3列的一维数组组成的
int a[2][3] = {
	{1,2,3},
  {4,5,6}
};
// 使用一级指针指向二维数组,利用的是C语言数组在内存中是按行展开的
int* p = &a[0][0];
// 访问二维数组,因为二维数组在内存中是按行排列的,所以可以直接访问每一个元素
for (int i = 0; i < 6; ++i) {
	cout<<*(p+i)<<" ";
}

6.2 使用指向数组的一级指针访问二维数组 -- 数组指针的应用

int a[2][3] = {
	{1,2,3},
{4,5,6}
};
// 使用指向数组类型int [3]的指针指向二维数组a,int [3]表示a的一维数组的类型
// 所以,p就是指向一个有3列一维数组的指针
// 定义一个指向int [3](一维数组)类型的指针p
int (*p)[3] = a;
// 访问二维数组
// *(q+j):表示存储在q中的一维数组,就是a的每行首元素的地址,*(q+j)=&a[j];
// *(q+j)+i:表示一维数组a[j]中的第i个元素的地址 *(q+j)+i = &a[j][i];
// *(*(q+j)+i):表示访问a[i][j]的内容
for (int j = 0; j < 2; ++j) {
	for (int i = 0; i < 3; ++i){
		cout<<*(*(q+j)+i)<<" ";
}
}

6.3 使用指向二维数组的指针访问二维数组 【重点】 -- 数组指针的应用

int arr[2][3] = {
         {1,2,3},
         {4,5,6}
 };
	// 定义一个指向int [2][3](两行三列二维数组)的指针
 int (*p)[2][3];
	// p 指向 arr
 p = &arr;
	// *p是二维数组的名字arr  === > (*p) == arr
	// (*p)[i][j]:访问数组的第i行j列元素  -- 指针加(),还是因为[]优先级高于*
 for (int i = 0; i < 2; ++i) {
     for (int j = 0; j < 3; ++j) {
         cout<<(*p)[i][j]<<" ";
     }
     cout<<endl;
 }

7.三维数组的指针访问 -- 其他高维指针自己弄吧,学过线性代数就好理解了

int main(int argv,char** argc) {
    // arr[2][3][4]:
    // 就是2个3行4列的二维数组组成的
    // 初始化时,{}表示一行,给两行二维数组即可
    int arr[2][3][4] = {
            {
                    {1,1,1,1},
                    {1,1,1,1},
                    {1,1,1,1}
             },
            {
                    {0,0,0,0},
                    {0,0,0,0},
                    {0,0,0,0}
            }
    };
    int (*p)[2][3][4];
    p = &arr;
    // *p = arr
    // 访问(i,j,k)位置的元素:(*p)[i][j][k]
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 3; ++j) {
            for (int k = 0; k < 4; ++k) {
                cout<<(*p)[i][j][k]<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }
    return 0;
}

8. 指针数组和数组指针 -- 区别:*,[]优先级不同搞出来的

指针数组 - 是一个存放指针的数组

形如:
// [] 优先级高于*,所以arr和[]先结合,所以是指针数组
int *arr[3]; // 定义一个存储3个int*(int型指针)类型的数组
void (*at[3])(char ch); 
// 定义一个存储3个void (*)(char) [-- 指向void ()(char)函数类型的指针]类型的数组
// 定义一个存储3个指向void ()(char)函数类型的指针的数组

数组指针 - 是一个指向数组的指针

形如:
// []优先级高于*,但是()优先级高于[],arr先和*结合,所以是指针
int (*arr)[3];  
// 定义一个指向int [3](有3个元素的一维数组)的指针
// 定义一个指向含有3个元素的一维数组的指针

int (*arr)[2][3];

定义一个指向高维数组的指针书写方式

1.先找指针要指向的类型 
2.在添加(*指针名)
    
eg:定义一个指向2行3列的数组的指针
1.指向的类型为:int [2][3];
2.int (*arr)[2][3]; // arr是一个指向二维数组([2][3])的指针
3.*arr:表示二维数组
posted @ 2022-08-09 01:00  nanfengnan  阅读(27)  评论(0编辑  收藏  举报