C++中容易忽略的一些细节

85 篇文章 0 订阅

(1)字符串函数strlen是如何用的。

strlen的原型为: 

size_t strlen ( const char * str );

作用是返回C字符串的字符个数(不包含‘/0’), 使必须注意str是pointer to the null-terminated byte string to be examined。也就是说str指向的字符串必须以“\0”结尾, 否则出错的。

可能实现方式:

// strlen:  return length of string str
int strlen( const char* str )
{
    int count;
    for ( count = 0; *str != '\0'; ++str )
        ++count;
    return count;
}


使用如下:

<span style="font-size:14px;">#include <iostream>
#include <cstring>
using namespace std;

int main()
{
    char m[] = "123"; // 4, 默认添加'/0', 表示字符串结束
    char n[5] = {'a', 'b', 'c'}; // 最后一个默认加'/0', 表示字符串结束
    cout << sizeof(m) << endl; //4
    cout << strlen(m) << endl; // 3
    cout << sizeof(n) << endl; //5
    cout << strlen(n) << endl; // 3

    return 0;
}
</span>

运行结果如下:

 

再比如:

<span style="font-size:14px;">#include <iostream>
#include <cstring>
using namespace std;


int main() {
    char n[] = {'a', 'b', 'c', '\0'}; // 最后一个不会默认加'/0', 表示字符串结束
    cout << sizeof(n) << endl; //5
    cout << strlen(n) << endl; // 3


    char m[] = {'a'};
    cout << sizeof(m) << endl; // 课件对于字符数组, 不会默认加'/0', 都需要手动加
    cout << strlen(m) << endl; // 任意数, 为4,因为没加\0


    return 0;
}</span>
注意, 对于字符数组来说, 它并不在乎中间或者末尾是否有没有'\0'结束字符, 因为数组知道他有多少个元素。 况且'\0'对她来说是一个合法的字符。 对于字符串库函数strlen, strcpy,等,  并不知道这个字符串是来自一个字符数组, 因为你传递进去的知识字符指针。 而字符指针(char* p)除了它的类型和值外, 不包含其他任何信息, 这些库函数总是假设你提供的字符指针指向的内存空间中的某个字节存放着一个'\0', 它会很傻的知道找到这一个'\0'才肯罢休。 如果你能够保证通过字符数组下标访问数组中的每一个元素, 就没有必要在字符数组尾部加一个'\0', 但是大多数情况下我们无法保证, 因为大多数情况下, 总是吧字符数组用作字符串缓重区(例如 char buf[1024]), 所以应当在字符数组尾部放入这个麻烦的‘\0’.
运行结果如下:


(2)使用数组的名字作为函数的参数, 数组名字退化成const的指针了。 此时取sizeof(), 总是返回4(指针存放的是地址)

如下例子:

<span style="font-size:14px;"><span style="font-size:14px;">#include <iostream>


using namespace std;


void func(int a[]) {
    cout << sizeof(a) << endl; //为指针变量的大小4
    cout << sizeof(a) / sizeof(a[0]) << endl;
    cout << a[5] << endl;
}


int main() {
    int a[4] = {1, 2, 3, 4};
    func(a); // a退化成了一个指针变量
    cout << sizeof(a) << endl;
    cout << a[5] << endl; // 不会报错?!, 显示的是某个任意值
    cout << sizeof(a) / sizeof(a[0]);
    return 0;
}
</span></span>

运行结果为4

所以, 在函数内部, 必须传进数组大小的信息n。 无法通过sizeof求取元素的个数。 另外使用数组的的时候不要越界了。




(3)if 语句中如果进行float的值与0比较, 格式是什么

<span style="font-size:14px;">const float EPSILON = 1e-6;
if((x >=  -EPSILON) && (x <= EPSILON)) {
    //
}</span>

(4)C++程序中调用C编译器编译过的函数, 为什么要加extern “C”

C++语言支持函数重载, 而C语言不支持函数重载。 函数被C++编译器编译和被C编译器编译后生成的内部名字是不一样的。

假如某个函数原型为:

<span style="font-size:14px;">void f(int x,  int y);</span>
该函数被C编译器编译后的内部名字为_foo, 而C++编译器则会生成像_foo_int_int之类的名字。 C++提供了C连接交换指定符号extern "C"来解决名字匹配问题(兼容)。

(5) 如何不调用C++/C的字符串函数, 编写函数strcpy。

<span style="font-size:14px;">char* strcpy(char* strDest, const char* strSrc) {
    assert((strDest!=NULL)&&(strSrc!=NULL));
    char* address = strDest;
    while((*strDest++ = *strSrc++) != '\0');
    return address;
}
</span>

另一种实现方法:

// strcpy: copy src to dst; array subscript version
void strcpy( char* dst, char* src )
{
    int idx = 0;
    while ( ( dst[ idx ] = src[ idx ] ) != '\0' )
        ++idx;
}

问题一: strcpy能把strSrc的内容拷贝到strDest, 为什么还要返回char*类型的返回值?

答案: 为了实现链式表达式。 例如: int length = strlen(strcpy(strDest,  "hello world")); 因为strcpy第二个参数是const char*, 所以可以接受字符串常量。 

问题二: 什么是assert语句?

 这是一个定义在<assert.h>头文件中的宏, 用来测试断言的。 一个断言本质是是程序员的假设。, 如果这个假设被违反, 就表明这个程序有严重的错误。 例如, 一个结社只接受否空指针的函数, 可以写成: 

<span style="font-size:14px;">assert(p != NULL);</span>
一个失败的断言会中断程序。 断言不应该用来捕捉意料之中的错误。 例如malloc, 或者freopen的失败。

(6)编写字符串类

<span style="font-size:14px;">class String {
public:
    String(const char *str = ""); // 普通构造函数
    String(const String &other); // 拷贝构造函数
    ~String(); // 析构函数
    String& operator=(const String &other);// 重载赋值运算符
private:
    char *m_data;
    
};

// String的普通构造函数
String::String(const char* str) {
    if(str==NULL) {
        m_data = new char[1];
        *m_data = '\0';
    }
    else {
        int length = strlen(str);
        m_data = new char(length + 1);
        strcpy(m_data, str);
    }
}

// String的析构函数
String::~String() {
    delete[] m_data;
}

// 拷贝构造函数
String::String(const String& other) {
    int length = strlen(other.m_data);
    m_data = new char[length + 1];
    strcpy(m_data, other.m_data);
}

// 赋值函数
String &String::operator=(const String& other) {
    // 检查自我赋值
    if(this != other) {
        char* temp = new char[strlen(other.m_data) + 1];
        strcpy(temp, other.m_data);
        //释放原有内存资源
        delete[] m_data;
        m_data = temp;
    }
    // 返回本对象的应用
    return *this;
}</span>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值