如何在C ++中使用memset?

时间:2019-06-05 15:13:02

标签: c++ string initialization string-literals memset

我来自Python背景,最近学习C ++。我正在学习一个名为threading.Thread的C / C ++函数,并从https://www.geeksforgeeks.org/memset-in-cpp/网站上的在线示例中发现了一些编译错误:

multiprocessing.Process

使用单引号't'时出错
这样会打印出多余的字符。

memset

在双引号中使用“ t”时出错

/**
 * @author      : Bhishan Poudel
 * @file        : a02_memset_geeks.cpp
 * @created     : Wednesday Jun 05, 2019 11:07:03 EDT
 * 
 * Ref: 
 */

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

int main(int argc, char *argv[]){
    char str[] = "geeksforgeeks";

    //memset(str, "t", sizeof(str));
    memset(str, 't', sizeof(str));

    cout << str << endl;

    return 0;
}

如何在C ++中使用内存集?

进一步学习
这里给出了缺点tttttttttttttt!R@` 的优秀教程: https://web.archive.org/web/20170702122030/https:/augias.org/paercebal/tech_doc/doc.en/cp.memset_is_evil.html

4 个答案:

答案 0 :(得分:64)

此声明

char str[] = "geeksforgeeks";

声明一个字符数组,其中包含一个字符串,该字符串是包含终止零符号'\0'的字符序列。

您可以按照以下等效方式想象该声明

char str[] = 
{ 
    'g', 'e', 'e', 'k', 's', 'f', 'o', 'r', 'g', 'e', 'e', 'k', 's', '\0'
};

此函数memset

的调用
memset(str, 't', sizeof(str));

覆盖数组的所有字符,包括结尾的零。

所以下一条语句

cout << str << endl;

导致不确定的行为,因为它会输出字符直到遇到终止的零为止。

您可以改写

#include <iostream>
#include <cstring>

int main()
{
    char str[] = "geeksforgeeks";

    std::memset( str, 't', sizeof( str ) - 1 );

    std::cout << str << '\n';
}

或采用以下方式

#include <iostream>
#include <cstring>

int main()
{
    char str[] = "geeksforgeeks";

    std::memset( str, 't', std::strlen( str ) );

    std::cout << str << '\n';
}

这将使终止零在数组中保持不变。

如果要覆盖数组的所有字符(包括结尾的零),则应替换此语句

std::cout << str << '\n';

此声明

std::cout.write( str, sizeof( str ) ) << '\n';

如下面程序所示,因为该数组现在不包含字符串。

#include <iostream>
#include <cstring>

int main()
{
    char str[] = "geeksforgeeks";

    std::memset( str, 't', sizeof( str ) );

    std::cout.write( str, sizeof( str ) ) << '\n';
}

至此通话

memset(str, "t", sizeof(str));

然后,第二个参数的类型(即类型const char *)与具有int类型的第二个函数参数的类型不对应。参见函数的声明

void * memset ( void * ptr, int value, size_t num );

因此,编译器会发出错误消息。

除了字符数组(即使在C ++中也经常使用)之外,您还可以使用模拟字符串的标准类std::string(或std::basic_string)。

在这种情况下,不需要使用标准的C函数memset来用单个字符填充字符串。最简单的方法是以下

#include <iostream>
#include <string>

int main()
{
    std::string s( "geeksforgeeks" );

    s.assign( s.length(), 't' );

    std::cout << s << '\n';
}

另一种方法是使用标头std::fill中声明的标准算法std::fill_n<algorithm>。例如

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>

int main()
{
    std::string s( "geeksforgeeks" );

    std::fill( std::begin( s ), std::end( s ), 't' );

    std::cout << s << '\n';
}

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>

int main()
{
    std::string s( "geeksforgeeks" );

    std::fill_n( std::begin( s ), s.length(), 't' );

    std::cout << s << '\n';
}

您甚至可以通过以下方式之一使用类replace的方法std::string

#include <iostream>
#include <string>

int main()
{
    std::string s( "geeksforgeeks" );

    s.replace( 0, s.length(), s.length(), 't' );

    std::cout << s << '\n';
}

#include <iostream>
#include <string>

int main()
{
    std::string s( "geeksforgeeks" );

    s.replace( std::begin( s ), std::end( s ), s.length(), 't' );

    std::cout << s << '\n';
}

答案 1 :(得分:32)

  

使用单引号't'时出错。这会打印出多余的字符。

那是因为您重写了空终止符。

终止符是数组大小的一部分(数组不是魔术),尽管it's not part of the logical string size

所以,我想你是说:

memset(str, 't', strlen(str));
//               ^^^^^^

  

在双引号中使用“ t”时出错

完全不同的东西。您告诉计算机将字符串中的每个字符都设置为一个字符串。没有道理;无法编译。


  

如何在C ++中使用memset?

不要。

将类型安全的std::fillstd::beginstd::end结合使用:

std::fill(std::begin(str), std::end(str)-1, 't');

(如果您担心性能,请不要:这将仅通过模板专门化工作委托给memset,不需要进行优化,而不会牺牲类型安全性; {{3} }。)

或者只是一个std::string开始。 ?


  

我正在从example here in libstdc++学习C ++中的功能memset,示例如下所示

请勿尝试从随机网站学习C ++。让自己https://www.geeksforgeeks.org/memset-in-cpp/

答案 2 :(得分:5)

这是memset的正确语法...

void* memset( void* dest, int ch, std::size_t count );
  

将值ch转换为unsigned char,并将其复制到dest所指向对象的每个第一个计数字符中。如果对象是可能重叠的子对象或不是TriviallyCopyable(例如,标量,C兼容结构或琐碎可复制类型的数组),则行为是不确定的。如果count大于dest指向的对象的大小,则行为是不确定的。

source

对于第一种语法memset(str, 't', sizeof(str));。编译器抱怨尺寸过大。它打印18次tttttttttttttt!R@。我建议尝试将sizeof(str) -1用于char数组。

对于第二语法memset(str, "t", sizeof(str));,您要提供的第二个参数是字符串。这就是编译器抱怨错误的原因:从“ const char *”到“ int”的无效转换

答案 3 :(得分:5)

弗拉德(Vlad)很有帮助地回答了您问题的第一部分,但我觉得第二部分可以更直观地解释:

正如其他人所提到的,'t'字符,而"t" string ,字符串的末尾有一个空终止符。这使"t"的数组不是一个而是两个个字符-['t', '\0']!这使memset的错误更直观-可以很容易地将单个char强制转换为int,但是当给定char数组时,它会阻塞。就像在Python中一样,int(['t', '\0'])(或ord(['t', '\0']))不会计算。