Question

Je travaille en C et je dois concaténer quelques petites choses.

En ce moment, j'ai ceci:

message = strcat("TEXT ", var);

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

Maintenant, si vous avez de l’expérience en C, je suis sûr que vous réalisez que cela vous donne une erreur de segmentation lorsque vous essayez de l’exécuter. Alors, comment puis-je y remédier?

Était-ce utile?

La solution

En C, " chaînes " ne sont que de simples char tableaux. Par conséquent, vous ne pouvez pas les concaténer directement avec d'autres & "Chaînes &" ;.

Vous pouvez utiliser la fonction strcat qui ajoute la chaîne pointée par src à la fin de la chaîne pointée par dest:

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

Voici un exemple tiré de cplusplus.com :

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

Pour le premier paramètre, vous devez fournir le tampon de destination lui-même. Le tampon de destination doit être un tampon de tableau de caractères. Exemple: char buffer[1024];

Assurez-vous que le premier paramètre dispose de suffisamment d'espace pour stocker ce que vous essayez de copier. Si vous en avez la possibilité, il est plus prudent d’utiliser des fonctions telles que: strcpy_s et strcat_s où vous devez explicitement spécifier la taille du tampon de destination.

Remarque : un littéral de chaîne ne peut pas être utilisé comme tampon car il s'agit d'une constante. Ainsi, vous devez toujours allouer un tableau de caractères pour le tampon.

La valeur de retour de <=> peut simplement être ignorée, elle renvoie simplement le même pointeur que celui qui a été transmis comme premier argument. Il est là pour votre commodité et vous permet de chaîner les appels en une seule ligne de code:

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

Votre problème pourrait donc être résolu comme suit:

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

Autres conseils

Évitez d'utiliser strcat en code C. Le moyen le plus propre et, le plus important, le plus sûr est d’utiliser snprintf :

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

Certains commentateurs ont soulevé le problème suivant: le nombre d'arguments peut ne pas correspondre à la chaîne de format et le code sera toujours compilé, mais la plupart des compilateurs envoient déjà un avertissement si tel est le cas.

Mes amis, utilisez str n cpy (), str n cat () ou s n printf ().
Si vous dépassez votre espace tampon, tout ce qui suivra en mémoire sera mis au rebut!
(Et souvenez-vous de laisser de l'espace pour le caractère nul '\ 0' final!)

Malloc et realloc sont également utiles si vous ne savez pas à l'avance combien de chaînes sont concaténées.

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

Les chaînes peuvent également être concaténées au moment de la compilation.

#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 */ 
                ;

N'oubliez pas d'initialiser le tampon de sortie. Le premier argument de strcat doit être une chaîne terminée par un caractère NULL avec suffisamment d'espace supplémentaire alloué pour la chaîne résultante:

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

Le premier argument de strcat () doit pouvoir contenir suffisamment d’espace pour la chaîne concaténée. Allouez donc un tampon avec suffisamment d’espace pour recevoir le résultat.

char bigEnough[64] = "";

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

/* and so on */

strcat () concaténera le deuxième argument avec le premier argument et stockera le résultat dans le premier argument. Le caractère renvoyé * est tout simplement ce premier argument, et uniquement pour votre commodité.

Vous n'obtenez pas de chaîne nouvellement allouée avec le premier et le deuxième arguments concaténés, ce que je suppose que vous attendiez en fonction de votre code.

Comme les gens l'ont souligné, la manipulation des chaînes s'est beaucoup améliorée. Vous voudrez peut-être apprendre à utiliser la bibliothèque de chaînes C ++ à la place des chaînes de style C. Cependant, voici une solution en C pur

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

Je ne suis pas sûr que ce soit correct / sûr mais pour le moment je ne pourrais pas trouver un meilleur moyen de le faire en ANSI C.

Le meilleur moyen de le faire sans avoir une taille de tampon limitée est d'utiliser asprintf ()

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

C’est un comportement indéfini de tenter de modifier les littéraux de chaîne, ce qui ressemble à quelque chose comme:

strcat ("Hello, ", name);

va essayer de faire. Il essaiera de clouer la chaîne name à la fin du littéral de chaîne "Hello, ", qui n'est pas bien défini.

Essayez quelque chose comme ça. Il réalise ce que vous semblez vouloir faire:

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

Ceci crée une zone tampon qui est autorisée à être modifiée, puis copie à la fois le littéral de chaîne et tout autre texte. Soyez juste prudent avec les débordements de mémoire tampon. Si vous contrôlez les données d'entrée (ou si vous les vérifiez à l'avance), vous pouvez utiliser des tampons de longueur fixe comme ceux que j'ai.

Sinon, vous devez utiliser des stratégies d'atténuation, telles que l'allocation de suffisamment de mémoire à partir du segment de mémoire pour vous assurer de pouvoir la gérer. En d'autres termes, quelque chose comme:

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.

Vous pouvez écrire votre propre fonction qui fait la même chose que strcat() mais cela ne change rien:

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

Si les deux chaînes ensemble comptent plus de 1000 caractères, la chaîne sera coupée à 1000 caractères. Vous pouvez modifier la valeur de MAX_STRING_LENGTH selon vos besoins.

En supposant que vous avez un caractère [fixed_size] plutôt qu'un caractère *, vous pouvez utiliser une seule macro créative pour le faire en une seule fois avec un <<cout<<like classement (& (plutôt!% s le% s disjoint) \ n & ";"! & "; que &"; ", &"; format de style printf & ";). Si vous travaillez avec des systèmes embarqués, cette méthode vous permettra également d’omettre Malloc et la grande *printf famille de fonctions telles que snprintf() (Ceci empêche également à dietlibc de se plaindre de * 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);
  • Note 1, vous n'utiliseriez généralement pas argv [0] comme ceci - juste un exemple
  • Remarque 2, vous pouvez utiliser n’importe quelle fonction générant un caractère *, y compris des fonctions non standard telles que itoa () pour convertir des entiers en types chaîne.
  • Remarque 3, si vous utilisez déjà printf dans votre programme, il n’ya aucune raison de ne pas utiliser snprintf (), car le code compilé serait plus volumineux (mais intégré et nettement plus rapide)
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;
}

Vous essayez de copier une chaîne dans une adresse allouée de manière statique. Vous devez chatter dans un tampon.

Spécifiquement:

... snip ...

destination

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

Il y a un exemple ici aussi.

Si vous avez de l'expérience en C, vous remarquerez que les chaînes ne sont que des tableaux de caractères dont le dernier caractère est nul.

C'est tout à fait gênant car vous devez trouver le dernier caractère pour pouvoir ajouter quelque chose. strcat le fera pour vous.

Donc, strcat cherche dans le premier argument un caractère nul. Ensuite, il remplacera ceci par le contenu du deuxième argument (jusqu'à ce que tout se termine par un zéro).

Voyons maintenant votre code:

message = strcat("TEXT " + var);

Vous ajoutez ici quelque chose au pointeur sur le texte " TEXT " (le type de " TEXT & "est const char *. Un pointeur.).

Cela ne fonctionnera généralement pas. Modifier également le & Quot; TEXT & Quot; tableau ne fonctionnera pas car il est généralement placé dans un segment constant.

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

Cela pourrait mieux fonctionner, sauf que vous essayez encore de modifier des textes statiques. strcat n'alloue pas de nouvelle mémoire pour le résultat.

Je proposerais plutôt de faire quelque chose comme ceci:

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

Lisez la documentation de sprintf pour vérifier ses options.

Et maintenant un point important:

Assurez-vous que le tampon dispose de suffisamment d’espace pour contenir le texte ET le caractère nul. Quelques fonctions peuvent vous aider, par exemple strncat et les versions spéciales de printf qui allouent le tampon à votre place. Ne pas garantir que la taille de la mémoire tampon entraînera une corruption de la mémoire et des bogues exploitables à distance.

C’était ma solution

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

mais vous devez spécifier le nombre de chaînes que vous allez concaténer

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

Essayez quelque chose de similaire à ceci:

#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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top