内存,字符串和终结者



我必须编写一个函数,用字符串的内容填充指定长度的 char* 缓冲区。如果绳子太长,我只需要剪掉它。缓冲区不是由我分配的,而是由我的函数的用户分配的。我尝试了这样的事情:

int writebuff(char* buffer, int length){
    string text="123456789012345";
    memcpy(buffer, text.c_str(),length);
    //buffer[length]='';
    return 1;
}

int main(){
    char* buffer = new char[10];
    writebuff(buffer,10);
    cout << "After: "<<buffer<<endl;
}

我的问题是关于终结者的:它应该存在还是不存在?这个函数用于更广泛的代码中,有时当需要剪切字符串时,我似乎会遇到奇怪的字符问题。

关于要遵循的正确程序的任何提示?

C 样式字符串必须以零字符结尾 ''

此外,您的代码还有另一个问题 - 它可能会尝试从源字符串的末尾进行复制。这是典型的未定义行为。它可能看起来像是有效的,直到在堆内存块的末尾分配字符串并且副本进入内存的受保护区域并发生惊人的失败。应仅复制缓冲区长度或字符串长度的最小值

附言为了完整起见,这里有一个很好的函数版本。感谢 Naveen 指出终止空值中的逐一错误。我冒昧地使用您的返回值来指示返回字符串的长度,或者如果传入的长度为 <= 0,则所需的字符数。

int writebuff(char* buffer, int length)
{
    string text="123456789012345";
    if (length <= 0)
        return text.size();
    if (text.size() < length)
    {
        memcpy(buffer, text.c_str(), text.size()+1);
        return text.size();
    }
    memcpy(buffer, text.c_str(), length-1);
    buffer[length-1]='';
    return length-1;
}

如果要将缓冲区视为字符串,则应以 NULL 终止它。为此,您需要使用 memcpy 复制length-1字符并将length-1字符设置为 .

似乎正在使用C++ - 鉴于此,最简单的方法是(假设接口规范需要 NUL 终止)

int writebuff(char* buffer, int length)
{
  string text = "123456789012345";
  std::fill_n(buffer, length, 0); // reset the entire buffer
  // use the built-in copy method from std::string, it will decide what's best.
  text.copy(buffer, length);
  // only over-write the last character if source is greater than length
  if (length < text.size())
    buffer[length-1] = 0;
  return 1; // eh?
}

char * 缓冲区必须以 null 结尾,除非您在任何地方显式传递长度并说明缓冲区不会以 null 终止。

是否应该用终止字符串取决于writebuff函数的规范。如果你在调用函数后buffer应该是一个有效的 C 样式字符串,你应该用 终止它。

但请注意,c_str()将以终止,因此您可以使用text.size() + 1作为源字符串的大小。另请注意,如果length大于字符串的大小,则将复制比text当前代码提供的更远的复制(您可以使用min(length - 2, text.size() + 1/*trailing */)来防止这种情况,并设置buffer[length - 1] = 0来限制它)。

main中分配的buffer泄露了,顺便说一句

我的问题是关于终结者的:它应该存在还是不存在?

是的。它应该在那里。否则你以后怎么知道字符串的结尾?cout怎么会知道呢?它会继续打印垃圾,直到遇到值恰好是的垃圾。您的程序甚至可能崩溃。

作为旁注,您的程序正在泄漏内存。它不会释放它分配的内存。但是既然你退出了main(),那就没多大关系了;毕竟,一旦程序结束,无论您是否释放它,所有内存都将返回操作系统。但总的来说,如果你不要忘记自己解除分配内存(或任何其他资源),它是一个很好的做法。

我同意 Necrolis 的观点,strncpy 是要走的路,但如果字符串太长,它不会得到空终止符。你有一个正确的想法来放置一个显式终止符,但正如你所写的那样,你的代码把它放在了末尾。(这是在 C 中,因为你似乎做的 C 比 C++ 多?

int writebuff(char* buffer, int length){
    char* text="123456789012345";
    strncpy(buffer, text, length);
    buffer[length-1]='';
   return 1;
}

它应该最挑衅地在那里*,这可以防止对于缓冲区来说太长的字符串完全填充它,并在以后访问它时导致溢出。 虽然 IMO,应该使用strncpy而不是 memcpy ,但您仍然必须 null 终止它。(您的示例也会泄漏内存)。

*如果您有任何疑问,请走最安全的路线!

首先,我不知道writerbuff是否应该终止字符串。这是一个设计问题,由决定writebuff应该存在的人来回答。

第二,以你的具体例子作为一个整体,有两个问题。一种是将未终止的字符串传递给operator<<(ostream, char*) 。其次是注释掉的行写入超出指示缓冲区的末尾。这两者都会调用未定义的行为。

(第三是设计缺陷——你知道length总是小于text的长度吗?

试试这个:

int writebuff(char* buffer, int length){
  string text="123456789012345";
  memcpy(buffer, text.c_str(),length);
  buffer[length-1]='';
  return 1;
}

int main(){
  char* buffer = new char[10];
  writebuff(buffer,10);
  cout << "After: "<<buffer<<endl;
}
  1. main()中,你应该delete你用new.分配的缓冲区,或者静态分配它(char buf[10])。 是的,它只有 10 个字节,是的,它是一个内存"池",而不是泄漏,因为它是一次性分配,是的,您需要在程序的整个运行时间内使用该内存。 但这仍然是一个好习惯。

  2. 在 C/C++ 中,字符缓冲区的一般约定是它们是 null 终止的,因此除非明确告诉我不要这样做,否则我会包含它。 如果我这样做了,我会注释它,甚至可能在 char * 参数上使用 typedef 或名称,表明结果是一个不以 null 结尾的字符串。

相关内容

  • 没有找到相关文章