Использование strcat в C
Итак, у меня есть следующий код, который добавляет строку в другую в С#, обратите внимание, что это просто пример, поэтому предоставление альтернативных методов конкатенации строк в С# не является обязательным, это просто упростите пример.
string Data = "";
Data +="\n\nHTTP/1.1 " + Status_code;
Data += "\nContent-Type: " + Content_Type;
Data += "\nServer: PT06";
Data += "\nContent-Length: " + Content_Lengt;
Data += "\nDate: " + Date;
Data += "\n" + HTML;
Теперь я хотел бы сделать то же самое в C, и я пытаюсь сделать это следующим образом.
time_t rawtime;
time ( &rawtime );
char *message = "\n\nHTTP/1.1 ";
message = strcat(message, Status_code);
message = strcat(message, "\nContent-Type: ");
message = strcat(message, Content_Type);
message = strcat(message, "\nServer: PT06");
message = strcat(message, "\nContent-Length: ");
message = strcat(message, Content_Lengt);
message = strcat(message, "\nDate: ");
message = strcat(message, ctime(&rawtime));
message = strcat(message, "\n");
message = strcat(message, HTML);
Теперь это дает мне ошибку Сегмента, я знаю, почему, я получаю доступ и читаю в памяти, что я не должен. Но вопрос в том, как я его решаю? Могу ли я использовать string.h и просто сделать это так же, как в С#?
Ответы
Ответ 1
Изменить
char *message = "\n\nHTTP/1.1 ";
к
char message[1024];
strcpy(message,"\n\nHTTP/1.1 ");
и вы должны быть в порядке, до общей длины сообщения 1023.
Изменить: (согласно комментарию mjy). Использование strcat таким способом - отличный способ получить переполнение буфера. Вы можете легко написать небольшую функцию, которая проверяет размер буфера и длину входящего добавления строки, чтобы преодолеть это, или использовать realloc в динамическом буфере. IMO, бремя на программиста, чтобы проверить правильные размеры буфера, где они используются, например, с помощью sprintfs и других функций C строк. Я предполагаю, что C используется по С++ по соображениям производительности, и, следовательно, STL не является вариантом.
Изменить: согласно запросу от комментария Filip простая реализация strcat на основе буфера с фиксированным размером char:
char buffer[MAXSIZE] = "";
int mystrcat(char *addition)
{
if (strlen(buffer) + strlen(addition) + sizeof(char) >= MaxSize)
return(FAILED);
strcat(buffer,addition);
return(OK);
}
Использование динамического распределения:
char *buffer = NULL;
int mystrcat(char *addition)
{
buffer = realloc(buffer, strlen(buffer) + strlen(addition) + sizeof(char));
if (!buffer)
return(FAIL);
strcat(buffer, addition);
return(OK);
}
В этом случае вам нужно освободить свой буфер вручную, когда вы закончите с ним. (Обрабатывается деструкторами в эквивалентах С++)
Добавление (Pax):
Хорошо, поскольку на самом деле вы не объяснили, почему вам нужно было создать message[1024]
, вот оно.
С char * x = "hello" фактические байты ('h', 'e', 'l', 'l', 'o', 0) (нуль на конце) сохраняются в область памяти, отдельную от переменных (и, вполне возможно, только для чтения), и переменная x устанавливается на нее. После нулевого, возможно, что-то еще очень важно. Таким образом, вы не можете добавить к этому вообще.
С char x[1024]; strcpy(x,"hello");
вы сначала выделяете 1K om память, которая полностью посвящена x. Затем вы копируете "привет" в него и все еще оставляете немного места в конце для добавления большего количества строк. У вас не будет проблем, пока вы не добавите больше, чем разрешено 1K.
Конечное добавление (Pax):
Ответ 2
Интересно, почему никто не упомянул snprintf()
от stdio.h
. То, что C способ выводить несколько значений, и вам даже не придется предварительно конвертировать ваши примитивы в строки.
В следующем примере используется стековый буфер фиксированного размера. В противном случае вы должны malloc()
сохранить буфер (и сохранить его размер), что позволило бы realloc()
при переполнении...
char buffer[1024];
int len = snprintf(buffer, sizeof(buffer), "%s %i", "a string", 5);
if(len < 0 || len >= sizeof(buffer))
{
// buffer too small or error
}
Изменить: Вы также можете использовать функцию asprintf()
. Это широко распространенное расширение GNU и часть TR 24731-2 (что означает, что это может привести к следующему стандарту C). Пример сверху читал
char * buffer;
if(asprintf(&buffer, "%s %i", "a string", 5) < 0)
{
// (allocation?) error
}
Помните free()
буфер, когда он будет выполнен с его помощью!
Ответ 3
Начните с использования более безопасной функции strncat
. В общем, всегда используйте более безопасные "n" функции, которые не будут переполняться, если размер строки больше определенного размера.
В C вам нужно самостоятельно позаботиться о размерах строк. Таким образом, вам нужно знать, насколько велика результирующая строка и будет она приспособлена для нее. Если вы знаете размеры всех строк в левой части, вы должны создать буфер, достаточно большой, чтобы удерживать результирующую строку.
Ответ 4
указывает на char const [], с которым вы не можете писать, но точно, где именно пишет strcat. Вам нужно malloc() достаточно большой буфер.
Ответ 5
Как уже говорилось ранее, вам нужно написать достаточно большой буфер. К сожалению, это очень много работы. Большинство приложений C, которые имеют дело со строками, используют динамически изменяемый строковый буфер для выполнения конкатенаций.
glib включает реализацию этой glib строк, которую я рекомендую использовать для любого приложения, которое сильно использует строки. Это упрощает управление памятью и предотвращает переполнение буфера.
Ответ 6
Не видел упоминания функции strlcpy, strlcat, которая похожа на функции "n", кроме того, учитывает конечный 0. Оба имеют третий аргумент, указывающий максимальную длину выходного буфера и находятся в string.h.
Пример:
char blah[]="blah";
char buffer[1024];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);
Выведет "herro!!! blah"
char blah[]="blah";
char buffer[10];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);
выводит "herro!!! b" из-за ограниченного размера буфера [], без segfault. ^^
Только проблема заключается не в том, что все платформы, как представляется, включают ее в свой libc (например, linux._.), большинство из всех BSD-переменных DO, похоже, имеют это.
В этом случае код для обеих функций можно найти здесь и легко добавить: strlcpy, strlcat,
остальная часть string.h
Ответ 7
Безопасный способ сделать это в классическом стиле C:
char *strconcat(char *s1, char *s2)
{
size_t old_size;
char *t;
old_size = strlen(s1);
/* cannot use realloc() on initial const char* */
t = malloc(old_size + strlen(s2) + 1);
strcpy(t, s1);
strcpy(t + old_size, s2);
return t;
}
...
char *message = "\n\nHTTP/1.1 ";
message = strconcat (message, Status_code);
message = strconcat (message, "\nContent-Type: ");
Теперь вы можете сказать много плохих вещей об этом: он неэффективен, он фрагментирует вашу память, это уродливо... но это более или менее то, что любой язык с оператором конкатенации строк и строками типа C (с нулевым завершением) (за исключением того, что на большинстве этих языков будет встроена сборка мусора).