必背八股文-C/C++(2)

指针常量、常量指针、常量引用

int * const p //指针常量

int a,b;

int * const p=&a //指针常量

//那么分为一下两种操作

*p=9;//操作成功

p=&b;//操作错误

因为声明了指针常量,说明指针变量不允许修改。如同指针指向一个地址该地址不能被修改,但是该地址里的内容可以被修改。

const int *p=&a //常量指针

//那么分为一下两种操作

*p=9;//操作错误

p=&b;//操作成功

因为常量指针本质是指针,并且这个指针是一个指向常量的指针,指针指向的变量的值不可通过该指针修改,但是指针指向的值可以改变。

常量引用:

double a;

const int &r = a;    //正确

const int &r = 10;  //正确

关键字inline的作用

inline是C++语言中的一个关键字,用于修饰函数,在编译器编译时将函数调用处直接展开为函数体,从而避免了函数调用的开销,提高程序的运行速度。具体作用如下:

• inline修饰的函数在编译时将被直接展开为函数调用处的代码,从而避免了函数调用的开销,提高程序的运行速度。

• inline函数一般都定义在头文件中,可以被多个源文件调用,不会引起重复定义的错误。

• inline函数不能使用递归调用,也不能包含复杂的循环结构或switch语句等。

内联函数与一般函数的区别

• 内联函数在编译器编译时将函数调用处直接展开为函数体,避免了函数调用的开销,提高程序的运行速度。

• 一般函数在编译器编译时不会展开函数调用,需要在程序运行时进行函数调用,会产生一定的函数调用开销。

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

内联函数的优点:

• 内联函数可以减少函数调用的开销,提高程序的运行速度。

• 内联函数定义在头文件中,可以方便地被多个源文件调用,不会引起重复定义的错误。

内联函数的缺点:

• 内联函数会增加代码的体积,导致可执行文件的大小增加。

• 内联函数不能包含复杂的循环结构、递归调用等,否则可能会导致代码膨胀。

内联函数适用场景:

• 内联函数适合于被频繁调用、函数体较小、函数参数较简单的函数,可以减少函数调用的开销,提高程序的运行速度。

• 内联函数不适合于包含复杂的循环结构、递归调用等的函数,否则可能会导致代码膨胀,降低程序的运行效率。

内联函数和宏定义的区别

宏定义是预处理器处理的文本替换,而内联函数是编译器处理的类型安全函数。

• 宏定义:宏定义是由预处理器(preprocessor)处理的文本替换。宏定义通常使用指令定义。当预处理器遇到宏定义调用时,它会将宏定义展开,将宏定义直接替换到调用的地方。宏定义的优点是没有函数调用开销,但它也有以下缺点:

1)由于使用宏的时候,只是进行简单的字符替换,不会对类型进行检查,存在安全隐患。

2)由于宏是直接替换的,所以会导致代码稍微长一点。

3)嵌套定义过多可能会影响程序的可读性,会容易出错。

4)边界效应。由于宏定义的时候,其各个分量未加括号,而在使用宏定义的时候,传递的参数是变量的表达式,然后经过系统展开后,由于优先级的原因,导致其结果不是你所希望的.

• 内联函数:内联函数是编译器处理的,使用关键字声明。内联函数的主要目的是建议编译器将函数调用替换为函数体,从而消除函数调用开销。内联函数具有以下优点:

1)inline定义的内联函数,函数代码被放入符号表中,在使用时进行替换(像宏一样展开),效率很高

2)类的内联函数也是函数。编绎器在调用一个内联函数,首先会检查参数问题,保证调用正确,像对待

真正函数一样,消除了隐患及局限性。

3)inline可以作为类的成员函数,也可以使用所在类的保护成员及私有成员。

缺点:

1)内联函数以复制为代价,活动产函数开销

2)如果函数的代码较长,使用内联将消耗过多内存

3)如果函数体内有循环,那么执行函数代码时间比调用开销大。

为什么不能把所有的函数写成内联函数?

• 内联函数展开后会增加代码的体积,导致可执行文件的大小增加,如果定义过多的内联函数会导致程序的运行速度变慢。

• 内联函数不能包含复杂的循环结构、递归调用等,否则可能会导致代码膨胀,降低程序的运行效率。

• 内联函数的展开由编译器决定,不一定能够被成功展开为内联代码。

构造函数、析构函数、虚函数可否声明为内联函数?

• 构造函数和析构函数声明为内联函数 构造函数和析构函数可以声明为内联函数,但是一般不建议这么做。因为构造函数和析构函数需要完成一些复杂的操作,如初始化和清理资源等,定义为内联函数可能会导致代码膨胀,降低程序的运行效率。

• 虚函数声明为内联函数 虚函数可以声明为内联函数,但是虚函数的内联并不是静态绑定的,而是动态绑定的。这就意味着需要在程序运行时才能确定具体调用哪个函数,这可能会影响内联函数的展开效果,导致程序的运行速度变慢。因此,建议将虚函数定义在类的外部,并在函数定义前添加virtual关键字,这样可以避免内联函数的展开问题。

strcpy和memcpy的区别是什么?

• strcpy函数是字符串拷贝函数,用于将一个字符串从源地址拷贝到目标地址。它是以'\0'为字符串结束标志的,会一直拷贝直到遇到'\0'字符为止。

• memcpy函数是内存拷贝函数,用于将指定长度的内存从源地址拷贝到目标地址。它不关心拷贝的内存中是否存在'\0'字符。

strcpy、sprintf与memcpy这三个函数的不同之处

• strcpy函数是字符串拷贝函数,用于将一个字符串从源地址拷贝到目标地址。

• sprintf函数是格式化输出函数,可以将多个参数按照指定的格式输出到一个字符串中。

• memcpy函数是内存拷贝函数,用于将指定长度的内存从源地址拷贝到目标地址。

strcpy函数和strncpy函数的区别?哪个函数更安全?

• strcpy函数是字符串拷贝函数,它将一个字符串从源地址拷贝到目标地址,直到遇到'\0'字符为止。如果源字符串长度超过了目标字符串的长度,会导致目标字符串缓冲区溢出,从而引发安全问题。

• strncpy函数也是字符串拷贝函数,它将一个字符串从源地址拷贝到目标地址,但是不同的是,它最多只会拷贝指定长度的字符,如果源字符串长度超过了目标字符串的长度,那么只会拷贝部分字符,并在目标字符串的末尾自动添加'\0'字符,避免了缓冲区溢出的问题。因此,strncpy函数比strcpy函数更安全。

C语言中memcpy和memmove是一样的吗?

memcpy和memmove都是用于内存拷贝的函数,但是它们的实现方式有所不同。

• memcpy:函数原型:void *memcpy(void *dest, const void *src, size_t n);它从 src 指向的位置开始,复制 n 个字节到 dest 指向的位置。当源和目标内存区域重叠时,memcpy 的行为是未定义的。也就是说,如果你使用 memcpy 复制重叠的内存区域,结果可能是不可预测的。

• memmove:函数原型:void *memmove(void *dest, const void *src, size_t n);它也从 src 指向的位置开始,复制 n 个字节到 dest 指向的位置。与 memcpy 不同的是,memmove 能够处理源和目标内存区域重叠的情况。它确保复制操作在重叠的情况下也能正确进行,不会出现数据损坏的问题。

因此,尽管两者的功能类似,但在源地址和目标地址有重叠的情况下,应该使用memmove函数,而不是memcpy函数。

手写函数:strlen()、strcpy()、strstr()、strcat()、strcmp()、memcpy()

// 计算字符串长度
int strlen(const char* str) {
    int len = 0;
    while (*str != '\0') {
        len++;
        str++;
    }
    return len;
}

// 拷贝字符串
char* strcpy(char* dest, const char* src) {
    char* ret = dest;
    while (*src != '\0') {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = '\0';
    return ret;
}

// 在字符串中查找子串
char* strstr(const char* str1, const char* str2) {
    const char* p1 = str1;
    const char* p2 = str2;
    const char* p3 = NULL;
    while (*p1 != '\0') {
        p3 = p1;
        while (*p2 != '\0' && *p1 == *p2) {
            p1++;
            p2++;
        }
        if (*p2 == '\0') {
            return (char*)p3;
        }
        p1 = p3 + 1;
        p2 = str2;
    }
    return NULL;
}

// 连接字符串
char* strcat(char* dest, const char* src) {
    char* ret = dest;
    while (*dest != '\0') {
        dest++;
    }
    while (*src != '\0') {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = '\0';
    return ret;
}

// 比较字符串
int strcmp(const char* str1, const char* str2) {
    while (*str1 == *str2 && *str1 != '\0') {
        str1++;
        str2++;
    }
    return (*str1 - *str2);
}

// 内存拷贝
void* memcpy(void* dest, const void* src, size_t n) {
    char* p_dest = (char*)dest;
    const char* p_src = (const char*)src;
    while (n--) {
        *p_dest++ = *p_src++;
    }
    return dest;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值