Domanda

Sto lavorando in C e devo concatenare alcune cose.

In questo momento ho questo:

message = strcat("TEXT ", var);

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));

Ora, se hai esperienza in C, sono sicuro che ti rendi conto che questo ti dà un errore di segmentazione quando provi ad eseguirlo. Quindi, come posso aggirare questo?

È stato utile?

Soluzione

In C, " stringhe " sono semplici char matrici. Pertanto, non è possibile concatenarli direttamente con altre & Quot; stringhe & Quot ;.

Puoi usare la funzione strcat, che aggiunge la stringa puntata da src alla fine della stringa puntata da dest:

char *strcat(char *dest, const char *src);

Ecco un esempio da cplusplus.com :

char str[80];
strcpy(str, "these ");
strcat(str, "strings ");
strcat(str, "are ");
strcat(str, "concatenated.");

Per il primo parametro, è necessario fornire il buffer di destinazione stesso. Il buffer di destinazione deve essere un buffer di array di caratteri. Ad es .: char buffer[1024];

Assicurati che il primo parametro abbia spazio sufficiente per memorizzare ciò che stai cercando di copiare. Se disponibile, è più sicuro utilizzare funzioni come: strcpy_s e strcat_s in cui è necessario specificare esplicitamente la dimensione del buffer di destinazione.

Nota : una stringa letterale non può essere utilizzata come buffer, poiché è una costante. Pertanto, è sempre necessario allocare un array di caratteri per il buffer.

Il valore di ritorno di <=> può essere semplicemente ignorato, restituisce semplicemente lo stesso puntatore che è stato passato come primo argomento. È lì per comodità e ti consente di concatenare le chiamate in una riga di codice:

strcat(strcat(str, foo), bar);

Quindi il tuo problema potrebbe essere risolto come segue:

char *foo = "foo";
char *bar = "bar";
char str[80];
strcpy(str, "TEXT ");
strcat(str, foo);
strcat(str, bar);

Altri suggerimenti

Evita di utilizzare strcat nel codice C. Il modo più pulito e, soprattutto, più sicuro è utilizzare snprintf :

char buf[256];
snprintf(buf, sizeof buf, "%s%s%s%s", str1, str2, str3, str4);

Alcuni commentatori hanno sollevato il problema che il numero di argomenti potrebbe non corrispondere alla stringa di formato e che il codice continuerà a essere compilato, ma la maggior parte dei compilatori emette già un avviso se questo è il caso.

Gente, usate str n cpy (), str n cat () o s n printf ().
Il superamento dello spazio del buffer eliminerà tutto ciò che segue in memoria!
(E ricorda di lasciare spazio al carattere null '\ 0' finale!)

Anche malloc e realloc sono utili se non si conosce in anticipo quante stringhe vengono concatenate.

#include <stdio.h>
#include <string.h>

void example(const char *header, const char **words, size_t num_words)
{
    size_t message_len = strlen(header) + 1; /* + 1 for terminating NULL */
    char *message = (char*) malloc(message_len);
    strncat(message, header, message_len);

    for(int i = 0; i < num_words; ++i)
    {
       message_len += 1 + strlen(words[i]); /* 1 + for separator ';' */
       message = (char*) realloc(message, message_len);
       strncat(strncat(message, ";", message_len), words[i], message_len);
    }

    puts(message);

    free(message);
}

Le stringhe possono anche essere concatenate al momento della compilazione.

#define SCHEMA "test"
#define TABLE  "data"

const char *table = SCHEMA "." TABLE ; // note no + or . or anything
const char *qry =               // include comments in a string
    " SELECT * "                // get all fields
    " FROM " SCHEMA "." TABLE   /* the table */
    " WHERE x = 1 "             /* the filter */ 
                ;

Non dimenticare di inizializzare il buffer di output. Il primo argomento di strcat deve essere una stringa con terminazione null con spazio sufficiente allocato per la stringa risultante:

char out[1024] = ""; // must be initialized
strcat( out, null_terminated_string ); 
// null_terminated_string has less than 1023 chars

Il primo argomento di strcat () deve essere in grado di contenere spazio sufficiente per la stringa concatenata. Quindi allocare un buffer con spazio sufficiente per ricevere il risultato.

char bigEnough[64] = "";

strcat(bigEnough, "TEXT");
strcat(bigEnough, foo);

/* and so on */

strcat () concatenerà il secondo argomento con il primo argomento e memorizzerà il risultato nel primo argomento, il carattere restituito * è semplicemente questo primo argomento e solo per comodità dell'utente

Non ottieni una nuova stringa allocata con il primo e il secondo argomento concatenati, cosa che immagino ti aspettassi in base al tuo codice.

Come sottolineato dalle persone, la gestione delle stringhe è migliorata molto. Quindi potresti voler imparare come usare la libreria di stringhe C ++ invece di stringhe in stile C. Tuttavia, ecco una soluzione in puro C

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void appendToHello(const char *s) {
    const char *const hello = "hello ";

    const size_t sLength     = strlen(s);
    const size_t helloLength = strlen(hello);
    const size_t totalLength = sLength + helloLength;

    char *const strBuf = malloc(totalLength + 1);
    if (strBuf == NULL) {
        fprintf(stderr, "malloc failed\n");
        exit(EXIT_FAILURE);
    }

    strcpy(strBuf, hello);
    strcpy(strBuf + helloLength, s);

    puts(strBuf);

    free(strBuf);

}

int main (void) {
    appendToHello("blah blah");
    return 0;
}

Non sono sicuro che sia corretto / sicuro, ma in questo momento non sono riuscito a trovare un modo migliore per farlo in ANSI C.

Il modo migliore per farlo senza avere una dimensione del buffer limitata è usando asprintf ()

char* concat(const char* str1, const char* str2)
{
    char* result;
    asprintf(&result, "%s%s", str1, str2);
    return result;
}

È un comportamento indefinito tentare di modificare i valori letterali delle stringhe, che è qualcosa di simile:

strcat ("Hello, ", name);

tenterà di farlo. Tenterà di virare sulla name stringa alla fine della stringa letterale "Hello, ", che non è ben definita.

Prova qualcosa di simile. Raggiunge ciò che sembra stia cercando di fare:

char message[1000];
strcpy (message, "TEXT ");
strcat (message, var);

Questo crea un'area buffer a cui è consentito che può essere modificato e quindi copia sia la stringa letterale sia altro testo. Fai solo attenzione agli overflow del buffer. Se controlli i dati di input (o li controlli prima), va bene usare buffer a lunghezza fissa come ho fatto io.

Altrimenti, è necessario utilizzare strategie di mitigazione come l'allocazione di memoria sufficiente dall'heap per assicurarsi di poterlo gestire. In altre parole, qualcosa del tipo:

const static char TEXT[] = "TEXT ";

// Make *sure* you have enough space.

char *message = malloc (sizeof(TEXT) + strlen(var) + 1);
if (message == NULL)
     handleOutOfMemoryIntelligently();
strcpy (message, TEXT);
strcat (message, var);

// Need to free message at some point after you're done with it.

Puoi scrivere la tua funzione che fa la stessa cosa di strcat() ma che non cambia nulla:

#define MAX_STRING_LENGTH 1000
char *strcat_const(const char *str1,const char *str2){
    static char buffer[MAX_STRING_LENGTH];
    strncpy(buffer,str1,MAX_STRING_LENGTH);
    if(strlen(str1) < MAX_STRING_LENGTH){
        strncat(buffer,str2,MAX_STRING_LENGTH - strlen(buffer));
    }
    buffer[MAX_STRING_LENGTH - 1] = '\0';
    return buffer;
}

int main(int argc,char *argv[]){
    printf("%s",strcat_const("Hello ","world"));    //Prints "Hello world"
    return 0;
}

Se entrambe le stringhe insieme contengono più di 1000 caratteri, la stringa verrà tagliata a 1000 caratteri. Puoi modificare il valore di MAX_STRING_LENGTH in base alle tue esigenze.

Supponendo che tu abbia un carattere [fixed_size] piuttosto che un carattere *, puoi usare una singola macro creativa per fare tutto in una volta con un <<cout<<like ordine (" piuttosto% s il% s disgiunto \ n " ;, " rispetto a " ;, " formato stile printf "). Se stai lavorando con sistemi embedded, questo metodo ti permetterà anche di tralasciare malloc e la grande *printf famiglia di funzioni come snprintf() (Questo evita che dietlibc si lamenti anche di * printf)

#include <unistd.h> //for the write example
//note: you should check if offset==sizeof(buf) after use
#define strcpyALL(buf, offset, ...) do{ \
    char *bp=(char*)(buf+offset); /*so we can add to the end of a string*/ \
    const char *s, \
    *a[] = { __VA_ARGS__,NULL}, \
    **ss=a; \
    while((s=*ss++)) \
         while((*s)&&(++offset<(int)sizeof(buf))) \
            *bp++=*s++; \
    if (offset!=sizeof(buf))*bp=0; \
}while(0)

char buf[256];
int len=0;

strcpyALL(buf,len,
    "The config file is in:\n\t",getenv("HOME"),"/.config/",argv[0],"/config.rc\n"
);
if (len<sizeof(buf))
    write(1,buf,len); //outputs our message to stdout
else
    write(2,"error\n",6);

//but we can keep adding on because we kept track of the length
//this allows printf-like buffering to minimize number of syscalls to write
//set len back to 0 if you don't want this behavior
strcpyALL(buf,len,"Thanks for using ",argv[0],"!\n");
if (len<sizeof(buf))
    write(1,buf,len); //outputs both messages
else
    write(2,"error\n",6);
  • Nota 1, in genere non useresti argv [0] in questo modo - solo un esempio
  • Nota 2, è possibile utilizzare qualsiasi funzione che genera un carattere *, comprese le funzioni non standard come itoa () per convertire numeri interi in tipi di stringa.
  • Nota 3, se stai già utilizzando printf in qualsiasi punto del tuo programma non c'è motivo di non usare snprintf (), poiché il codice compilato sarebbe più grande (ma integrato e significativamente più veloce)
int main()
{
    char input[100];
    gets(input);

    char str[101];
    strcpy(str, " ");
    strcat(str, input);

    char *p = str;

    while(*p) {
       if(*p == ' ' && isalpha(*(p+1)) != 0)
           printf("%c",*(p+1));
       p++;
    }

    return 0;
}

Stai tentando di copiare una stringa in un indirizzo allocato staticamente. Devi entrare in un buffer.

In particolare:

... snip ...

destinazione

Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.

... snip ...

http://www.cplusplus.com/reference/clibrary/cstring /strcat.html

C'è anche un esempio qui.

Se hai esperienza in C noterai che le stringhe sono solo array di caratteri in cui l'ultimo carattere è un carattere null.

Ora questo è abbastanza scomodo in quanto devi trovare l'ultimo personaggio per aggiungere qualcosa. strcat lo farà per te.

Quindi strcat cerca nel primo argomento un carattere null. Quindi sostituirà questo con il contenuto del secondo argomento (fino a quando non termina in un null).

Ora esaminiamo il tuo codice:

message = strcat("TEXT " + var);

Qui stai aggiungendo qualcosa al puntatore al testo " TEXT " (il tipo di " TEXT " è const char *. Un puntatore.).

Di solito non funzionerà. Modifica anche il & Quot; TEXT & Quot; l'array non funzionerà in quanto viene solitamente posizionato in un segmento costante.

message2 = strcat(strcat("TEXT ", foo), strcat(" TEXT ", bar));

Potrebbe funzionare meglio, tranne per il fatto che stai di nuovo provando a modificare testi statici. strcat non sta allocando nuova memoria per il risultato.

Proporrei invece di fare qualcosa del genere:

sprintf(message2, "TEXT %s TEXT %s", foo, bar);

Leggi la documentazione di sprintf per verificarne le opzioni.

E ora un punto importante:

Assicurarsi che il buffer disponga di spazio sufficiente per contenere il testo E il carattere null. Esistono un paio di funzioni che possono aiutarti, ad esempio strncat e versioni speciali di printf che allocano il buffer per te. Non garantire la dimensione del buffer porterà alla corruzione della memoria e ai bug sfruttabili da remoto.

Questa era la mia soluzione

#include <stdlib.h>
#include <stdarg.h>

char *strconcat(int num_args, ...) {
    int strsize = 0;
    va_list ap;
    va_start(ap, num_args);
    for (int i = 0; i < num_args; i++) 
        strsize += strlen(va_arg(ap, char*));

    char *res = malloc(strsize+1);
    strsize = 0;
    va_start(ap, num_args);
    for (int i = 0; i < num_args; i++) {
        char *s = va_arg(ap, char*);
        strcpy(res+strsize, s);
        strsize += strlen(s);
    }
    va_end(ap);
    res[strsize] = '\0';

    return res;
}

ma devi specificare quante stringhe concatenerai

char *str = strconcat(3, "testing ", "this ", "thing");

Prova qualcosa di simile a questo:

#include <stdio.h>
#include <string.h>

int main(int argc, const char * argv[])
{
  // Insert code here...
  char firstname[100], secondname[100];
  printf("Enter First Name: ");
  fgets(firstname, 100, stdin);
  printf("Enter Second Name: ");
  fgets(secondname,100,stdin);
  firstname[strlen(firstname)-1]= '\0';
  printf("fullname is %s %s", firstname, secondname);

  return 0;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top