Как мне объединить константные / буквальные строки в C?

Я работаю на C, и мне нужно объединить несколько вещей.

Прямо сейчас у меня есть это:

message = strcat("TEXT ", var);

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

Теперь, если у вас есть опыт работы с C, я уверен, вы понимаете, что это вызывает ошибку сегментации, когда вы пытаетесь ее запустить. Итак, как мне обойти это?

Я хотел бы предложить вам использовать strlcat вместо strcat! gratisoft.us/todd/papers/strlcpy.html

activout.se 21.11.2008 16:37

Я хотел бы повторить это предложение. Strcat вызывает уязвимость для эксплойтов переполнения буфера. Кто-то может передать вашей программе данные, которые заставят ее выполнить произвольный код.

Brian 21.11.2008 17:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
383
2
1 143 174
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

Ответ принят как подходящий

В C «строки» - это просто массивы char. Следовательно, вы не можете напрямую связать их с другими «строками».

Вы можете использовать функцию strcat, которая добавляет строку, на которую указывает src, в конец строки, на которую указывает dest:

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

Вот пример с cplusplus.com:

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

Для первого параметра вам необходимо указать сам буфер назначения. Целевой буфер должен быть буфером массива символов. Например: char buffer[1024];

Убедись, что у первого параметра достаточно места для хранения того, что вы пытаетесь скопировать в него. Если это возможно, безопаснее использовать такие функции, как strcpy_s и strcat_s, где вы должны явно указать размер целевого буфера.

Примечание: строковый литерал нельзя использовать в качестве буфера, поскольку он является константой. Таким образом, вам всегда нужно выделять массив символов для буфера.

Возвращаемое значение strcat можно просто игнорировать, оно просто возвращает тот же указатель, который был передан в качестве первого аргумента. Это сделано для удобства и позволяет объединить вызовы в одну строку кода:

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

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

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

Не могли бы вы выделить жирным шрифтом "Будьте очень осторожны ..."? Это невозможно переоценить. Неправильное использование strcat, strcpy и sprintf составляет основу нестабильного / небезопасного программного обеспечения.

plinth 21.11.2008 16:33

«статическая строка» и «выделить свой собственный буфер» могут вводить в заблуждение, поскольку первое можно интерпретировать как «статический строковый буфер», а второе - как указание на динамическое выделение. +1, если вы измените значение на «Вы никогда не можете использовать строковый литерал в качестве буфера, вы всегда должны использовать свой собственный буфер» или подобное.

Robert Gamble 21.11.2008 17:02

Предупреждение: Как написано, этот код оставит в вашем коде огромную зияющую дыру для эксплойтов переполнения буфера.

Brian 21.11.2008 17:09

В приведенном выше примере невозможно использовать переполнение буфера. И да, я в целом согласен, я бы не стал использовать приведенный выше пример для неопределенных длин строк foo и bar.

Brian R. Bondy 21.11.2008 17:14

@psihodelia: Также не забывайте, что ложки намного лучше вилок! так что обязательно всегда используйте ложку!

Brian R. Bondy 12.05.2010 17:13

Не используйте strcat несколько раз! strcat должен проверить все предыдущие байты (поиск '\0'), которые вы уже объединили. Это бесполезная обработка.

dolmen 07.09.2010 20:13

Второй @dolmen, Джоэл Спольски написал по этому поводу довольно сложная статья. Должно быть обязательное чтение. ;-)

peter.slizik 14.08.2012 18:53

На самом деле строковые литералы можно объединить, просто поместив их рядом. например const char *str = "these" "strings" "are" "concatenated";.

bzim 15.01.2018 00:05

Не следует ли инициализировать начальный буфер символов нулями: char str[80] = {0};? Таким образом вы получите красивую строку с завершающим нулем.

Danijel 26.08.2020 16:08

Попытка изменить строковые литералы является неопределенным поведением, что примерно так:

strcat ("Hello, ", name);

постараюсь сделать. Он попытается прикрепить строку name к концу строкового литерала "Hello, ", который не определен должным образом.

Попробуйте что-нибудь вот это. Он достигает того, что вы пытаетесь сделать:

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

Это создает буферную область, которую разрешено изменять является, а затем копирует в нее строковый литерал и другой текст. Только будьте осторожны с переполнением буфера. Если вы контролируете входные данные (или проверяете их заранее), можно использовать буферы фиксированной длины, как у меня.

В противном случае вам следует использовать стратегии смягчения, такие как выделение достаточного количества памяти из кучи, чтобы гарантировать, что вы сможете справиться с этим. Другими словами, что-то вроде:

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.

Что произойдет, если в var / foo / bar больше 1000 символов? > :)

Geo 21.11.2008 17:20

Тогда вы получите переполнение буфера, которое вы можете добавить код для предварительной проверки (скажем, с помощью strlen). Но цель фрагмента кода - показать, как что-то работает, не загрязняя его слишком большим количеством дополнительного кода. В противном случае я бы проверял длину, было ли значение var / foo / bar null и т. д.

paxdiablo 22.11.2008 01:23

@paxdiablo: Но вы даже не упомянули об этом, отвечая на вопрос, где, по-видимому, это нужно упомянуть. Это делает ваш ответ опасный. Вы также не объяснили, почему этот код лучше, чем исходный код OP, за исключением мифа о том, что он «дает тот же результат, что и ваш оригинал» (тогда в чем будет смысл? Оригинал был сломанный!), Поэтому ответ также является неполный.

Lightness Races in Orbit 08.12.2011 00:09

Надеюсь, @PreferenceBean решила ваши проблемы, хотя и менее своевременно, чем в идеале :-) Дайте мне знать, если у вас все еще есть проблемы с ответом, и я улучшу его.

paxdiablo 22.02.2016 05:28

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

char bigEnough[64] = "";

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

/* and so on */

strcat () объединит второй аргумент с первым аргументом и сохранит результат в первом аргументе, возвращаемый char * - это просто этот первый аргумент и только для вашего удобства.

Вы не получаете вновь выделенную строку с объединенными первым и вторым аргументами, чего, как я полагаю, вы ожидали, основываясь на своем коде.

Вы пытаетесь скопировать строку в адрес, который назначен статически. Вам нужно попасть в буфер.

Конкретно:

... отрезать ...

назначения

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

... отрезать ...

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

Здесь тоже есть пример.

Избегайте использования strcat в коде C. Самый чистый и, главное, безопасный способ - использовать snprintf:

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

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

... но без ненужных и сбивающих с толку скобок для оператора sizeof. Они нужны только тогда, когда вам нужен размер фактического типа, а не объекта. Извините, питомец раздражен.

unwind 21.11.2008 16:23

Возможно, это лучший способ узнать размер буфера, если вам не указан указатель. Если у вас есть указатель, вы передадите длину буфера, на который он указывает.

Alex B 21.11.2008 16:26

Шашки, он имел в виду круглые скобки вокруг "buf" аргумента sizeof. они не требуются, если аргумент является выражением. Но я не понимаю, почему вам отказали. Я думаю, что ваш ответ лучший из всех, хотя это c99. (может из-за этого не согласны! ламеры!) +1

Johannes Schaub - litb 21.11.2008 16:27

О, понимание прочитанного -1. Но в любом случае я поддерживаю свой ответ.

Alex B 21.11.2008 16:28

sizeof () работает здесь только для char buf [...]. НЕ для char * buf = malloc (...). Между массивами и указателями не так много различий, но это одно из них!

Mr.Ree 21.11.2008 16:28

Да, отсюда и мой комментарий о динамически выделяемых буферах.

Alex B 21.11.2008 16:30

Также он пытается выполнить конкатенацию. Конкатенация с использованием snprintf() - это БОЛЬШОЙ нет.

Leonardo Herrera 21.11.2008 18:05

@ Леонардо, ты можешь сказать, почему?

quinmars 22.11.2008 02:13

Что ж, есть некоторый риск, что вы добавите еще один, скажем, «str5» и забудете дополнительный «% s» в строке формата - или наоборот. Вылетит только у вас (если вам повезет) во время выполнения. Кроме того, это кажется излишним, учитывая альтернативы безопасно для "strcat".

Christian.K 25.11.2008 10:39

@ Christian.K ах, но достойный компилятор предупредит вас, если вы это сделаете.

Alex B 25.12.2010 04:37

@MrRee: Различия между указателями и массивами огромны и полны! Не всегда разница в том, как вы их использовать. Кроме того, указатели и динамическое размещение - действительно ортогональные концепции.

Lightness Races in Orbit 08.12.2011 00:11

какой тип str1 должен быть у str2? Могу ли я использовать std::string или разрешен только char*?

Oleg Vazhnev 24.03.2014 22:10

@javapowered %s ожидает только char*.

Alex B 28.03.2014 11:47

Одна из моих любимых головокружений - это такие люди, как @unwind, которые настаивают на бессмысленном различии между sizeof(x) и sizeof x. Обозначения в скобках всегда работают, а нотации без скобок работают только иногда, поэтому всегда используйте обозначения в скобках; это простое правило, которое следует запомнить, и оно безопасно. Это переходит в религиозный аргумент - я был вовлечен в дискуссии с теми, кто возражал и раньше, - но простота «всегда использовать круглые скобки» перевешивает любые достоинства отказа от их использования (IMNSHO, конечно). Это представлено для баланса.

Jonathan Leffler 31.03.2014 04:22

согласовано. не забываем, что sizeof следует интерпретировать как вызов функции. И что sizeof (x + 1) и sizeof (x) + 1 - очень разные вещи.

stackPusher 02.06.2015 04:47

1- Лучший ответ, аккуратно !. 2- Для меня sprintf работает без sizeof в качестве второго аргумента. Нашел int sprintf(char *str, const char *format, ...) в tutorialspoint.com/c_standard_library/c_function_sprintf.htm

aerijman 27.12.2020 17:54

Если у вас есть опыт работы с C, вы заметите, что строки представляют собой только массивы символов, в которых последний символ является нулевым символом.

Это довольно неудобно, так как вам нужно найти последний символ, чтобы что-то добавить. strcat сделает это за вас.

Таким образом, strcat ищет в первом аргументе нулевой символ. Затем он заменит это содержимым второго аргумента (до тех пор, пока это не закончится нулевым значением).

Теперь пройдемся по вашему коду:

message = strcat("TEXT " + var);

Здесь вы что-то добавляете к указателю на текст «ТЕКСТ» (тип «ТЕКСТ» - const char *. Указатель.).

Обычно это не работает. Также не сработает изменение массива «ТЕКСТ», поскольку он обычно помещается в постоянный сегмент.

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

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

Я бы предложил вместо этого сделать что-то вроде этого:

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

Прочтите документацию sprintf, чтобы проверить его возможности.

А теперь важный момент:

Убедитесь, что в буфере достаточно места для хранения текста И нулевого символа. Есть несколько функций, которые могут вам помочь, например, strncat и специальные версии printf, которые выделяют буфер для вас. Необеспечение размера буфера приведет к повреждению памяти и ошибкам, которые можно использовать удаленно.

Тип "TEXT" - char[5], нетconst char*. Он распадается на char* в большинстве случаев. По причинам обратной совместимости строковые литералы не являются const, но попытка их изменить приводит к неопределенному поведению. (В C++ строковыми литералами являются const.)

Keith Thompson 08.12.2011 00:41

Друзья, используйте strпcpy (), strпcat () или sпprintf ().
Превышение вашего буферного пространства приведет к удалению всего остального в памяти!
(И не забудьте оставить место для завершающего нулевого символа '\ 0'!)

Вы не только должны помнить о том, чтобы оставить место для символа NULL, вам нужно не забыть добавлять для символа NULL. strncpy и strncat не делают этого за вас.

Graeme Perrow 21.11.2008 16:36

Эм-м-м? strncpy () и strncat () обязательно добавляют завершающий символ. На самом деле они добавляют слишком много. По крайней мере, до тех пор, пока в буфере остается место, что является огромной ловушкой для этих вызовов. Не рекомендуется.

unwind 21.11.2008 16:42

@unwind, я думаю, что смысл Грэма в том, что если буфер слишком мал, strncpy или strncat добавят нет завершающий '\ 0'.

quinmars 21.11.2008 16:45

если n <strlen () + 1, ноль не добавляется. если n == strlen () + 1, добавляется один нуль. если n> strlen () + 1, добавляется много нулей. Это называется ПРОГРАММИРОВАНИЕ.

Mr.Ree 21.11.2008 16:46

Еще лучше, предпочитайте OpenBSD strlcpy, strlcat (легко переносить в ваш собственный проект).

Alex B 21.11.2008 16:46

Да, я тоже предпочитаю strl *. Но в этом случае я думаю, что ваше предложение snprintf - лучший способ.

quinmars 21.11.2008 17:01

snprintf - это хорошо, strncpy / strncat - наихудшая из возможных рекомендаций, strlcpy / strlcat - намного лучше.

Robert Gamble 21.11.2008 17:04

Не используйте strncpy(). Это нет - «более безопасная» версия strcpy(). Целевой массив символов может быть без нужды дополнен дополнительными символами '\0' или, что еще хуже, может остаться незавершенным (то есть не строкой). (Он был разработан для использования со структурой данных, которая больше не используется, символьным массивом, дополненным до конца нулями или более символами '\0'.)

Keith Thompson 08.12.2011 00:39

В strncpy и strncat этот n - это максимальное количество символов для копирования, а не размер целевого буфера. Это и незавершенные строки в случае усечения, а также различная обработка усечения на разных платформах также делают его опасным. Пожалуйста, рассмотрите strlcpy и strlcat. Смотрите также мою небольшую статью на эту тему: gergap.wordpress.com/2013/04/05/…

user3150128 02.08.2018 12:14

Не забудьте инициализировать выходной буфер. Первым аргументом strcat должна быть строка с завершающим нулем и достаточным дополнительным пространством, выделенным для результирующей строки:

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

Также malloc и realloc полезны, если вы заранее не знаете, сколько строк объединяется.

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

Это закончится бесконечным циклом, когда num_words>INT_MAX, возможно, вам стоит использовать size_t для i

12431234123412341234123 25.03.2017 15:48

Как отмечали люди, обработка строк значительно улучшилась. Так что вы можете узнать, как использовать строковую библиотеку C++ вместо строк в стиле C. Однако вот решение в чистом 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;
}

Я не уверен, правильно ли это / безопасно, но сейчас я не мог найти лучшего способа сделать это в ANSI C.

<string.h> - это стиль C++. Вам нужен "string.h". Вы также дважды рассчитываете strlen(s1), что не требуется. s3 должен быть длинным.
Mooing Duck 08.12.2011 00:08

@MooingDuck: "string.h" - ерунда.

sbi 08.12.2011 00:15

Я какое-то время не использовал струны в стиле C. Не стесняйтесь размещать исправленную версию.

Nils 08.12.2011 00:16

@MooingDuck: Это неправильно. #include <string.h> является правильным C. Используйте угловые скобки для стандартных и системных заголовков (включая <string.h>), кавычки для заголовков, которые являются частью вашей программы. (#include "string.h" будет работать, если у вас нет собственного файла заголовка с таким именем, но все равно используйте <string.h>.)

Keith Thompson 08.12.2011 00:33

Обратите внимание, что это зависит от специфичных для C99 функций: объявлений и операторов смешивания и массивов переменной длины (VLA). Также обратите внимание, что VLA не предоставляют механизма для обнаружения или обработки сбоев распределения; если недостаточно места для выделения VLA, поведение вашей программы не определено.

Keith Thompson 08.12.2011 00:35

Выложил исправленную версию, пожалуйста, пересмотрите свое голосование.

Nils 08.12.2011 00:38

Вы можете безопасно использовать strcat, а не strncat, поскольку вы уже гарантировали, что цель достаточно велика.

Keith Thompson 08.12.2011 00:43

@KeithThompson согласен, пока перешел только на strcpy.

Nils 08.12.2011 00:46

@KeithThompson: Теперь он заслуживает одобрения, превратив мой -1 в +1. (Этот ответ был «вдохновлен» дискуссией об обработке строк C и C++ в чате C++. Я думаю, Нильс, этим фиаско вы довольно эффективно продемонстрировали точку зрения своих оппонентов. :^>)

sbi 08.12.2011 19:14

Лучший способ сделать это без ограниченного размера буфера - использовать asprintf ()

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

Вы должны вернуть char *, а не const char *. Возвращаемое значение нужно будет передать в free.

Per Johansson 05.08.2013 17:31

К сожалению, asprintf - это всего лишь расширение GNU.

Calmarius 28.11.2013 20:24

Попробуйте что-нибудь подобное:

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

Предполагая, что у вас есть char [fixed_size], а не char *, вы можете использовать один творческий макрос, чтобы сделать все сразу с упорядочением <<cout<<like («скорее% s несвязный% s \ n», «чем», » формат стиля printf "). Если вы работаете со встроенными системами, этот метод также позволит вам исключить malloc и большое семейство функций *printf, например, snprintf() (это также не позволяет диетической библиотеке жаловаться на * 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);
  • Примечание 1, вы обычно не используете argv [0] в таком виде - просто пример
  • Примечание 2, вы можете использовать любую функцию, которая выводит символ *, включая нестандартные функции, такие как itoa (), для преобразования целых чисел в строковые типы.
  • Примечание 3: если вы уже используете printf где-либо в своей программе, нет причин не использовать snprintf (), поскольку скомпилированный код будет больше (но встроен и значительно быстрее)

Строки также могут быть объединены во время компиляции.

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

Вы можете написать свою собственную функцию, которая делает то же самое, что и strcat(), но это ничего не меняет:

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

Если обе строки вместе имеют длину более 1000 символов, она сократит строку до 1000 символов. Вы можете изменить значение MAX_STRING_LENGTH в соответствии со своими потребностями.

Я предвижу переполнение буфера, я вижу, что вы выделили strlen(str1) + strlen(str2), но вы пишете символы strlen(str1) + strlen(str2) + 1. Так вы действительно можете написать свою собственную функцию?

Liviu 29.07.2016 15:44

Ух ты! Ты никогда не освобождаешь память, гадкий, гадкий! return buffer; free(buffer);

Liviu 29.07.2016 15:46

Кстати, sizeof(char) == 1 (кроме того, есть и другие более тонкие ошибки ...) Теперь вы понимаете, почему вам не нужно писать свою собственную функцию?

Liviu 29.07.2016 15:46

@Liviu Я освобождаю память на линии free(buffer);.

Donald Duck 29.07.2016 15:47

@ Дак, вы освобождаете память после выхода из функции ... так что вы не освобождаете ее

Liviu 29.07.2016 15:48
char* mycat = strcat_const("Hello ","world"); free(mycat); Есть разница, правда?
Liviu 29.07.2016 15:49

@Liviu Это что-нибудь меняет? В этом примере я думаю, что он выполнит printf("%s",strcat_const("Hello ","world"));, а затем освободит память, поэтому, если вы добавите больше в функцию main(), она освободит память раньше. Скажите, если я ошибаюсь.

Donald Duck 29.07.2016 15:51
free(buffer); после того, как return buffer; никогда не запускается, посмотрите это в отладчике;) Теперь я понимаю: да, вам нужно освободить память в функции main
Liviu 29.07.2016 15:52

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

Liviu 29.07.2016 15:54

@Liviu Я отредактировал его, чтобы не было утечки памяти, но он поддерживает только ограниченное количество символов.

Donald Duck 29.07.2016 16:04

Что делать, если strlen(str1) >= MAX_STRING_LENGTH?

Liviu 29.07.2016 16:35

«Никакой нулевой символ не добавляется неявно в конце места назначения, если исходный код длиннее, чем num». cplusplus.com/reference/cstring/strncpy

Liviu 29.07.2016 16:37
buffer[strlen(buffer)] = '\0'; Есть что-то странное в этой строчке? Угадайте, как работает strlen;)! Я вернусь в понедельник, хороших выходных!
Liviu 29.07.2016 16:42

Думаю, должно работать, пересмотрю, когда вернусь! Вы можете добавить MAX_STRING_LENGTH в качестве параметра к strcat_const (конечно, с другим именем).

Liviu 29.07.2016 16:44

Это катастрофа :(, вы возвращаете адрес переменной стека (переменная buffer определена только внутри strcat_const). Я думаю, вам следует придерживаться решения с динамическим распределением.

Liviu 30.07.2016 00:52
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;
}

Это было мое решение

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

но вам нужно указать, сколько строк вы собираетесь объединить

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

Другие вопросы по теме