Мусор с strcpy и strcat

Я делаю клиент-серверный проект в Linux, и мне нужно объединить некоторые строки.

Я попробовал свой код в Visual Studio в Windows, и он отлично работает, но в Linux он дает мне какой-то мусор. У меня есть эта функция:

char* concat(char s1[], char s2[])
{
    int tam = 0;
    tam = strlen(s1);
    tam += strlen(s2);
    char *resultado =  malloc(sizeof(char) * tam) ;
    strcpy(resultado, s1); 
    strcat(resultado, s2); 
    return resultado;
}

Я читал, что проблема в отсутствии '\0', и я сделал это:

 char* concat(char s1[], char s2[])
{
    int tam = 0;
    tam = strlen(s1);
    tam += strlen(s2);
    char *resultado =  malloc(sizeof(char) * tam) ;
    resultado[tam+1] = '\0';
    strcpy(resultado, s1); 
    strcat(resultado, s2); 
    return resultado;
}

Первые 4 раза, когда я вызывал функцию, она работала (мусор пропал), но потом выдает `malloc(): повреждение памяти

Кто-нибудь может мне помочь?


person luidgi27    schedule 02.06.2015    source источник
comment
Вы выделяете tam символов для resultado, а затем добавляете \0 символа в tam+1. С индексами массива, основанными на 0, это означает, что вы на 2 превышаете выделенный лимит.   -  person    schedule 02.06.2015
comment
Вероятно, он работает в визуальной студии, потому что он щедрый и выделяет немного памяти сверх установленного вами предела. Но вы не можете полагаться на него, и запуск его в отладчике должен вызвать ошибку.   -  person    schedule 02.06.2015
comment
Прочтите о неопределенном поведении.   -  person Some programmer dude    schedule 02.06.2015
comment
Если по крайней мере s1 уже был malloc()ed ранее, вы можете возможно избежать копирования s1, используя realloc() с дополнительной длиной s2 (не забудьте убедиться, что есть место для дополнительного терминатора NUL). Затем просто добавьте s2 к перераспределенному s1.   -  person too honest for this site    schedule 03.06.2015


Ответы (3)


Вы не выделяете место для терминатора nul, что является очень распространенной ошибкой.

Предложения:

  1. Не используйте sizeof(char), это 1 по определению.
  2. Убедитесь, что malloc() не вернул NULL.
  3. Всегда помните nul байт.

Таким образом, ваш код будет исправлен следующим образом

char *resultado =  malloc(1 + tam);
if (resultado == NULL)
    pleaseDoNotUse_resultado();

Также обратите внимание, что эта строка

resultado[tam + 1] = '\0';

имеет несколько проблем

  1. tam + 1 нас за пределами выделенного блока.
  2. Вам не нужно этого делать, strcpy() сделает это за вас.

Использование strcat() и strcpy() в этой ситуации неэффективно, потому что вы уже знаете, сколько байт копировать, это

char *concat(char *s1, char *s2)
{
    size_t l1;
    size_t l2;
    char  *resultado

    if ((s1 == NULL) || (s2 == NULL))
        return NULL;
    l1 = strlen(s1);
    l2 = strlen(s2);
    resultado =  malloc(1 + l1 + l2) ;
    if (resultado == NULL)
        return NULL;
    memcpy(resultado     , s1, l1); 
    memcpy(resultado + l1, s2, l2); 

    resultado[l1 + l2] = '\0';
    return resultado;
}

будет более эффективным, даже когда вы проверяете NULL как параноик, это будет быстрее, чем strcpy() и strcat(), потому что вы будете вычислять длины только один раз.

person Iharob Al Asimi    schedule 02.06.2015

Вы не выделяете память для хранения нулевого значения. Помните, что strlen() не учитывает нуль-терминатор при вычислении длины строки. Тем не менее, вам нужно это место в целевом буфере, чтобы поместить нулевой терминатор.

Вы должны написать

 char *resultado =  malloc(tam + 1) ;

Также,

 resultado[tam+1] = '\0';

очень неправильно, потому что индексирование массива 0 основано на C, и здесь вы переполняете выделенную память (да, даже при выделении размера tam+1 также), что вызовет неопределенное поведение. Вам это совершенно не нужно, вы можете избавиться от этого.

После этого, в качестве примечания, как также упоминал Ихароб,

  1. Проверьте успешность malloc() перед использованием возвращенного указателя.
  2. В стандарте C sizeof(char) гарантированно будет 1. Нет необходимости использовать его при расчете размера для malloc().
person Natasha Dutta    schedule 02.06.2015

Вы должны выделить на один байт больше, чем длина результирующей строки:

char *resultado =  malloc(tam + 1) ;

Функции strcpy и strcat заботятся о завершающем NUL, вам не нужно добавлять его вручную.

person CiaPan    schedule 02.06.2015