如何在C ++中使用memset?

ast*_*123 28 c++ string initialization memset string-literals

我来自Python,最近学习C ++。我正在学习一个名为C / C ++的函数,memset并从https://www.geeksforgeeks.org/memset-in-cpp/网站中遵循在线示例,在该示例中我遇到了一些编译错误:

/**
 * @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;
}
Run Code Online (Sandbox Code Playgroud)

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

tttttttttttttt!R@`
Run Code Online (Sandbox Code Playgroud)

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

tttttttttttttt!R@`
Run Code Online (Sandbox Code Playgroud)

如何在C ++中使用memset?

进一步的研究此处
提供了具有缺点的优秀教程memsethttps : //web.archive.org/web/20170702122030/https : /augias.org/paercebal/tech_doc/doc.en/cp.memset_is_evil.html

Vla*_*cow 66

这个宣言

char str[] = "geeksforgeeks";
Run Code Online (Sandbox Code Playgroud)

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

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

char str[] = 
{ 
    'g', 'e', 'e', 'k', 's', 'f', 'o', 'r', 'g', 'e', 'e', 'k', 's', '\0'
};
Run Code Online (Sandbox Code Playgroud)

该函数的调用 memset

memset(str, 't', sizeof(str));
Run Code Online (Sandbox Code Playgroud)

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

所以下一条语句

cout << str << endl;
Run Code Online (Sandbox Code Playgroud)

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

你可以写

#include <iostream>
#include <cstring>

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

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

    std::cout << str << '\n';
}
Run Code Online (Sandbox Code Playgroud)

或以下方式

#include <iostream>
#include <cstring>

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

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

    std::cout << str << '\n';
}
Run Code Online (Sandbox Code Playgroud)

那就是使终止零在数组中保持不变。

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

std::cout << str << '\n';
Run Code Online (Sandbox Code Playgroud)

对于此声明

std::cout.write( str, sizeof( str ) ) << '\n';
Run Code Online (Sandbox Code Playgroud)

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

#include <iostream>
#include <cstring>

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

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

    std::cout.write( str, sizeof( str ) ) << '\n';
}
Run Code Online (Sandbox Code Playgroud)

至于这个电话

memset(str, "t", sizeof(str));
Run Code Online (Sandbox Code Playgroud)

那么第二个参数的类型(即类型const char *)与具有类型的第二个函数参数的类型不相符int。参见函数的声明

void * memset ( void * ptr, int value, size_t num );
Run Code Online (Sandbox Code Playgroud)

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

除了字符数组(即使在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';
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用标准算法std::fillstd::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';
}
Run Code Online (Sandbox Code Playgroud)

要么

#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';
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以使用以下方法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';
}
Run Code Online (Sandbox Code Playgroud)

要么

#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';
}
Run Code Online (Sandbox Code Playgroud)

  • 原始帖子清楚地表明用户正在尝试学习C ++。请至少指出,如果您使用`std :: string`,那么这些都无关紧要,应该在这里使用它而不是使用这种复杂的`C`东西。(尽管不是在课程开始时,但可能要知道) (19认同)
  • @JVApen原始帖子清楚地表明用户正在尝试了解如何将memset与字符数组一起使用。 (6认同)

Lig*_*ica 32

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

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

终止符是数组大小的一部分(数组不是魔术),尽管它不是逻辑字符串大小的一部分

因此,我认为您的意思是:

memset(str, 't', strlen(str));
//               ^^^^^^
Run Code Online (Sandbox Code Playgroud)

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

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


如何在C ++中使用memset?

别。

将type-safe std::fillstd::begin和结合使用std::end

std::fill(std::begin(str), std::end(str)-1, 't');
Run Code Online (Sandbox Code Playgroud)

(如果您担心性能,请不要担心:这将仅memset通过模板专门化(不需要优化)委托给可能的地方,而不会牺牲类型安全性;请参见libstdc ++中的示例。)

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


我正在从https://www.geeksforgeeks.org/memset-in-cpp/中学习C ++中的功能memset,示例如下

不要尝试从随机网站学习C ++。而是给自己买一本好书

  • 这个网站(geeksforgeeks)应该永远被禁止。 (6认同)
  • @ astro123:*从geeksforgeeks.org/memset-in-cpp在线学习*这是您的第一个问题。该教程的小例子中有一个严重的错误。这在geeksforgeeks.org上并不罕见。有*好的*东西,但常常与坏的东西混在一起,并且*直到您已经是专家*,您才不知道如何区分它们。与Stack Overflow不同,geeksforgeeks没有投票机制供人们查看帖子并指出其质量,因此您无法知道值得信任的帖子。 (6认同)
  • 不幸的是,在原始示例中,它确实是`sizeof`。遗憾的是,此类代码用于“教” c ++ :( (4认同)
  • @ astro123而是从一本好书上工作的另一个原因。C ++中有不同种类的文字,这与Python完全不同。 (3认同)

Aru*_*mar 5

这是memset的正确语法...

void* memset( void* dest, int ch, std::size_t count );
Run Code Online (Sandbox Code Playgroud)

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

来源

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

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


小智 5

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

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

  • 更准确地说,当传递“ t”时,将在“ t”中传递地址“ t”。因此,如果将其转换为“ memset”中的“ int”参数,则将是指向“ t”的指针转换为“ int”,而不是将字符串的值转换为“ int”。 (2认同)