Come usare memset in c++?




string initialization (4)

Sono di origine Python e recentemente ho imparato C ++. Stavo imparando una funzione C / C ++ chiamata memset e seguendo l'esempio online dal sito https://www.geeksforgeeks.org/memset-in-cpp/ dove ho ottenuto alcuni errori di compilazione:

/**
 * @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;
}

Errore durante l'utilizzo delle virgolette singole "t"
Questo stampa caratteri extra.

tttttttttttttt![email protected]`

Errore quando si usa "t" con virgolette doppie

$ g++ -std=c++11 a02_memset_geeks.cpp 
a02_memset_geeks.cpp:17:5: error: no matching function for call to 'memset'
    memset(str, "t", sizeof(str));
    ^~~~~~
/usr/include/string.h:74:7: note: candidate function not viable: no known
      conversion from 'const char [2]' to 'int' for 2nd argument
void    *memset(void *, int, size_t);
         ^
1 error generated.

Come usare il memset in C ++?

Ulteriore studio
Un eccellente tutorial con le lacune di memset è disponibile qui: https://web.archive.org/web/20170702122030/https:/augias.org/paercebal/tech_doc/doc.en/cp.memset_is_evil.html


Answer #1

Errore nell'uso di virgolette singole "t" Stampa caratteri extra.

Questo perché hai sovrascritto il terminatore null.

Il terminatore fa parte della dimensione dell'array (un array non è magico), sebbene non faccia parte della dimensione della stringa logica .

Quindi, penso che intendessi:

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

Errore quando si usa "t" con virgolette doppie

Cosa completamente diversa Hai detto al computer di impostare ogni carattere nella stringa, su una stringa. Non ha senso; non verrà compilato.

Come usare memset in C ++?

Non farlo.

Utilizzare lo std::fill sicuro in combinazione con std::begin e std::end :

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

(Se sei preoccupato per le prestazioni, non essere: questo semplicemente delegherà a memset ove possibile, attraverso la specializzazione del modello, l'ottimizzazione non richiesta, senza sacrificare la sicurezza del tipo, ad esempio qui in libstdc ++ .)

O solo una std::string per cominciare. 😊

Stavo imparando i memset di fuction in C ++ da https://www.geeksforgeeks.org/memset-in-cpp/ dove l'esempio è dato come sotto

Non tentare di imparare il C ++ da siti web casuali. Prendi invece un buon libro .


Answer #2

Vlad ha risposto alla prima parte della tua domanda, ma sento che la seconda parte potrebbe essere spiegata un po 'più intuitivamente:

Come altri hanno menzionato, 't' è un carattere mentre "t" è una stringa , e le stringhe hanno un terminatore nullo alla fine. Questo rende "t" un array di non uno ma due caratteri - ['t', '\0'] ! Questo rende l'errore di memset più intuitivo - può forzare un singolo char ad un int abbastanza facilmente, ma soffoca quando gli viene dato un array di char . Proprio come in Python, int(['t', '\0']) (o ord(['t', '\0']) ) non calcola.


Answer #3

Questa dichiarazione

char str[] = "geeksforgeeks";

dichiara un array di caratteri che contiene una stringa che è una sequenza di caratteri incluso il simbolo zero di terminazione '\0' .

Puoi immaginare la dichiarazione come il seguente modo equivalente

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

Questo richiamo della funzione memset

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

sovrascrive tutti i caratteri dell'array incluso lo zero finale.

Quindi la prossima affermazione

cout << str << endl;

produce un comportamento indefinito perché emette caratteri fino a quando non viene rilevato lo zero finale.

Potresti scrivere invece

#include <iostream>
#include <cstring>

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

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

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

O il seguente modo

#include <iostream>
#include <cstring>

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

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

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

Ciò mantiene lo zero terminale invariato nell'array.

Se si desidera sovrascrivere tutti i caratteri dell'array incluso lo zero di terminazione, è necessario sostituire questa dichiarazione

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

per questa affermazione

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

come viene mostrato nel programma qui sotto perché l'array ora non contiene una stringa.

#include <iostream>
#include <cstring>

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

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

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

Per quanto riguarda questa chiamata

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

quindi il tipo del secondo argomento (ovvero il tipo const char * ) non corrisponde al tipo del secondo parametro della funzione che ha il tipo int . Vedi la dichiarazione della funzione

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

Pertanto il compilatore emette un messaggio di errore.

Oltre agli array di caratteri (che sono usati molto spesso anche in C ++) puoi usare anche la classe standard std::string (o std::basic_string ) che simula le stringhe.

In questo caso non è necessario utilizzare la funzione C memset standard per riempire una stringa con un singolo carattere. Il modo più semplice per farlo è il seguente

#include <iostream>
#include <string>

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

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

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

Un altro modo è utilizzare l'algoritmo standard std::fill o std::fill_n dichiarato nell'intestazione <algorithm> . Per esempio

#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';
}

o

#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';
}

Puoi anche usare il metodo replace della classe std::string uno dei seguenti modi

#include <iostream>
#include <string>

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

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

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

O

#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';
}

Answer #4

Questa è la sintassi corretta per memset ...

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

Converte il valore ch in unsigned char e lo copia in ciascuno dei primi caratteri di conteggio dell'oggetto puntato da dest. Se l'oggetto è un subobject potenzialmente sovrapposto o non è TriviallyCopyable (ad esempio, una struttura scalare, compatibile con C o un array di tipo banalmente copiabile), il comportamento non è definito. Se il conteggio è maggiore della dimensione dell'oggetto puntato da dest, il comportamento non è definito.

( source )

Per la prima sintassi memset(str, 't', sizeof(str)); . Il compilatore si è lamentato a causa delle dimensioni extra. Stampa 18 volte [email protected] . Suggerisco di provare con sizeof(str) -1 per il char array.

Per la seconda sintassi memset(str, "t", sizeof(str)); stai fornendo il secondo parametro è una stringa. Questo è il motivo per cui il compilatore si lamenta dell'errore: conversione non valida da "const char *" a "int"





memset