Какой безопасный способ объединения строк в C? - PullRequest
5 голосов
/ 10 марта 2011

Мне нужно построить путь к файлу из двух строк.Я мог бы использовать это (не проверено, хотя):

/* DON'T USE THIS CODE! */
/* cmp means component */
char *path_cmp1 = "/Users/john/";
char *path_cmp2 = "foo/bar.txt";
unsigned len = strlen(path_cmp1);
char *path = path_cmp1;
for (int i = 0; i < strlen(path_cmp2); i++) {
  path[len + i] = path_cmp2[i];
}

, но это может привести к повреждению памяти, я думаю.Есть ли лучший способ сделать это, или есть функция для этого в стандартной библиотеке?

Ответы [ 9 ]

9 голосов
/ 10 марта 2011
#include <stdlib.h>
#include <string.h>

char *join(const char* s1, const char* s2)
{
    char* result = malloc(strlen(s1) + strlen(s2) + 1);

    if (result) // thanks @pmg
    {
        strcpy(result, s1);
        strcat(result, s2);
    }

    return result;
}

Это достаточно просто, чтобы записать на месте, особенно если у вас есть несколько строк для объединения.

Обратите внимание, что эти функции возвращают целевой аргумент, поэтому вы можете написать

char* result = malloc(strlen(s1) + strlen(s2) + 1);
assert(result);
strcat(strcpy(result, s1), s2);

но это менее читабельно.

5 голосов
/ 10 марта 2011
#include <stdio.h> 

char *a = "hello ";
char *b = "goodbye";
char *joined;

asprintf(&joined, "%s%s", a, b)
4 голосов
/ 10 марта 2011

В этом коде есть несколько проблем: 1 - вызов strlen для цикла for - плохая идея, он будет вычислять длину строки на каждой итерации, поэтому лучше вызывать его один раз перед циклом и сохранять результат в переменной.

2 - та же самая проблема strlen применяется к strlen (path_cmp1) внутри цикла, вызывает его перед циклом и увеличивает его размер.

В конце концов, лучше просто скопировать обе строки и сохранить их в динамически распределенной строке, например:

char *join_strings(const char* s1, const char* s2)
{
    size_t lens1 = strlen(s1);
    size_t lens2 = strlen(s2);

    //plus 1 for \0
    char *result = malloc(lens1 + lens2 + 1);

    if(result)
    {
        memcpy(result, s1, lens1);
        memcpy(result+lens1, s2, lens2+1);
    }

    //do not forget to call free when do not need it anymore
    return result;
}
3 голосов
/ 10 марта 2011
char *path_cmp1 = "/Users/john/";
char *path_cmp2 = "foo/bar.txt";

int firstLength = strlen(path_cmp1);
int secondLength = strlen(path_cmp2);
char *both = malloc(firstLength+secondLength+1);
memcpy(both, path_cmp1, firstLength);
memcpy(both+firstLength, path_cmp2, secondLength+1);
       // this +1 copyes the second string's null-terminator too.
3 голосов
/ 10 марта 2011

Для этого есть strcat и strncat.

2 голосов
/ 10 марта 2011

path - это просто указатель на path_cmp1, и вы пытаетесь получить доступ за концом массива. Очень редко это будет работать, но в подавляющем большинстве случаев вы будете вызывать повреждение памяти.

Как уже отмечали другие, используйте strcat для объединения строк.

2 голосов
/ 10 марта 2011

Как насчет strcat в string.h?

2 голосов
/ 10 марта 2011

Используйте strcat.(Вы правы, что ваш код приведет к повреждению памяти.)

2 голосов
/ 10 марта 2011

создайте новую строку с длиной обоих входов и strcpy / strcat входов и не забывайте нулевой терминатор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...