How do I concatenate const/literal strings in C?

前端 未结 17 1518
醉梦人生
醉梦人生 2020-11-21 23:45

I\'m working in C, and I have to concatenate a few things.

Right now I have this:

message = strcat(\"TEXT \", var);

message2 = strcat(strcat(\"TEXT          


        
相关标签:
17条回答
  • 2020-11-22 00:07

    Strings can also be concatenated at compile time.

    #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 */ 
                    ;
    
    0 讨论(0)
  • 2020-11-22 00:07

    Assuming you have a char[fixed_size] rather than a char*, you can use a single, creative macro to do it all at once with a <<cout<<like ordering ("rather %s the disjointed %s\n", "than", "printf style format"). If you are working with embedded systems, this method will also allow you to leave out malloc and the large *printf family of functions like snprintf() (This keeps dietlibc from complaining about *printf too)

    #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, you typically wouldn't use argv[0] like this - just an example
    • Note 2, you can use any function that outputs a char*, including nonstandard functions like itoa() for converting integers to string types.
    • Note 3, if you are already using printf anywhere in your program there is no reason not to use snprintf(), since the compiled code would be larger (but inlined and significantly faster)
    0 讨论(0)
  • 2020-11-22 00:10

    It is undefined behaviour to attempt to modify string literals, which is what something like:

    strcat ("Hello, ", name);
    

    will attempt to do. It will try to tack on the name string to the end of the string literal "Hello, ", which is not well defined.

    Try something this. It achieves what you appear to be trying to do:

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

    This creates a buffer area that is allowed to be modified and then copies both the string literal and other text to it. Just be careful with buffer overflows. If you control the input data (or check it before-hand), it's fine to use fixed length buffers like I have.

    Otherwise, you should use mitigation strategies such as allocating enough memory from the heap to ensure you can handle it. In other words, something like:

    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.
    
    0 讨论(0)
  • 2020-11-22 00:12

    Also malloc and realloc are useful if you don't know ahead of time how many strings are being concatenated.

    #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);
    }
    
    0 讨论(0)
  • 2020-11-22 00:13

    You can write your own function that does the same thing as strcat() but that doesn't change anything:

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

    If both strings together are more than 1000 characters long, it will cut the string at 1000 characters. You can change the value of MAX_STRING_LENGTH to suit your needs.

    0 讨论(0)
  • 2020-11-22 00:13
    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;
    }
    
    0 讨论(0)
提交回复
热议问题