尽管缺少空终止符,为什么指向char的C ++指针充当字符串?

时间:2016-06-13 07:18:37

标签: c++ c arrays string pointers

据我所知,C风格的字符串,即使在C ++而不是字符串类中使用,也需要一个空终止字符:

This is a string.\0

我的理解是,缺少空字符会导致程序继续读取字符串后的内存中的内容,直到找到空字符的二进制表示形式。这是非常明确的未定义行为。

在编写dtoi函数时(我想自己编写这个作为我正在做的不同练习项目的一部分 - 我知道已经有了库设施来实现这一点),我发现了不同的行为(特别是在创建时) invalid_argument例外的字符串。)

int dtoi(const char d){
    switch(d){ //using switch statement rather than d-'0' to support character sets with non-consecutive digits or digits that go from 9 to 0 rather than 0 to 9
        case '0':
            return 0;
        case '1':
            return 1;
        case '2':
            return 2;
        case '3':
            return 3;
        case '4':
            return 4;
        case '5':
            return 5;
        case '6':
            return 6;
        case '7':
            return 7;
        case '8':
            return 8;
        case '9':
            return 9;
        default:
            throw invalid_argument(((d == '\0') ? "null character" : &d) + string(" is not a valid digit character."));
    }
}

由于异常字符串开头的空字符导致它以第一个字符结束(即当一个空字符传递给我的dtoi实现时),我决定让它显示文本"空字符"而不是直接插入字符'\0'。为了实现这一点,我使用条件运算符。我无法使用(d == '\0') ? "null character" : d(注意它最后说d而不是&d),因为条件运算符可能会返回指向字符串文字中第一个字符的指针或直接的角色。为了看看发生了什么,我决定尝试&d,令我惊讶的是,它打印了在exception.what()中传递给函数的任何字符。我希望它提供一个指向传递的字符的指针,但是,然后继续读入随机存储器,直到它找到一个空字符。我尝试了多次,传入了多个不同的字符。为什么它的表现如此?我确实认为它是未定义的行为,它恰好在这里按预期工作吗?

3 个答案:

答案 0 :(得分:3)

关于C-Style字符串,你需要了解一个基本的东西,我们表示它们的方式(最后用' \ 0'的char数组)只是一个约定,没有类型(在C中)表示字符串。这意味着,从语言的角度来看,指向单个char的指针和指向char数组的开头的指针(可能是字符串)之间没有区别。所以它是一个使用这样一个指针的函数,以一种很好的方式解释它,并且该文档是你的朋友。

由于您使用的是C ++,我强烈建议您仅使用std :: string并保留C-Style字符串以便与C库向后兼容,这样可以避免很多问题。

答案 1 :(得分:2)

这里使用了

This operator+(指向单个char的非空终止的指针并不合适)。是的,绝对是undefined behavior

  

lhs - 以空终止数组

中第一个字符的字符串,字符或指针

只需将std::string常用类型修复即可:

((d == '\0') ? std::string("null character") : std::string(1, d))

并且不要形成switch - case这样的陈述。

答案 2 :(得分:0)

是的,它是未定义的行为,因为你读取随机内存。您应该做什么而不是整个凌乱的开关和?:运算符是这样的:

#include <cctype>

if(!std::isdigit(d))
{
  std::string err_str;

  if(d == '\0')
  {
    err_str = "Null character";
  }
  else
  {
    err_str = std::string(1, d);
  }
  err_str += " is not a valid digit character.";

  throw invalid_argument(err_str);
}

return (int)d - '0';