Использование strcat в C
хорошо, поэтому у меня есть следующий код, который добавляет строку к другой в C#, обратите внимание, что это просто пример, поэтому давать альтернативных методов string concatination в C# не обязательно, это просто для упрощения примера.
string Data = "";
Data +="nnHTTP/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 = "nnHTTP/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 и просто сделать это так же, как я сделал в C#?
7 ответов
изменить
char *message = "\n\nHTTP/1.1 ";
to
char message[1024];
strcpy(message,"\n\nHTTP/1.1 ");
и вы должны быть в порядке, до общей длины сообщения 1023.
Edit: (согласно комментарию mjy). Использование strcat таким образом-отличный способ получить переполнение буфера. Вы можете легко написать небольшую функцию, которая проверяет размер буфера и длину входящего добавления строки, чтобы преодолеть это, или использовать realloc в динамическом буфере. IMO, onus находится на программисте, чтобы проверить правильные размеры буфера, где они используются, как и с sprintfS и другие функции строк C. Я предполагаю, что C используется над C++ по соображениям производительности, и, следовательно, STL не является вариантом.
Edit: согласно запросу из комментария Филипа, простая реализация 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);
}
в этом случае вы должны освободить свой буфер вручную, когда вы закончите с ним. (Обрабатывается деструкторы в C++ эквиваленты)
Добавление (Pax):
ладно, так как вы на самом деле не объяснить почему вы должны создать message[1024]
, вот это.
С char * x = "hello" фактические байты ('h','e','l','l','o',0) (null на конце) хранятся в области памяти, отдельной от переменных (и, вполне возможно, только для чтения), и переменная x установлена для указания на нее. После нуля, вероятно, есть что-то еще очень важное. Поэтому вы не можете добавить к этому в все.
С char x[1024]; strcpy(x,"hello");
, вы сначала выделяете память 1K om, которая полностью посвящена x. Затем вы копируете в него "hello" и оставляете в конце довольно много места для добавления дополнительных строк. Вы не попадете в беду, пока не добавите больше, чем разрешено 1K-odd.
конец добавления (Pax):
интересно, почему никто не упомянул 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
}
Edit: вы также можете рассмотреть возможность использования
начните с использования safer . В общем случае всегда используйте более безопасные функции "n", которые не будут переполняться, если размер строки больше определенного размера.
В C вам нужно позаботиться о размерах строк самостоятельно. Поэтому вам нужно знать, насколько большой будет полученная строка, и приспособиться к ней. Если вы знаете размеры всех строк с левой стороны, вы должны создать буфер, достаточно большой, чтобы удерживать полученную строку.
сообщение указывает на char const[] , что вы не можете написать, но именно там strcat пишет. Вам нужно malloc () достаточно большой буфер.
Как уже говорилось ранее, вы должны написать в достаточно большой буфер. К сожалению, это очень большая дополнительная работа. Большинство приложений C, которые имеют дело со строками, используют динамически изменяемый строковый буфер для выполнения конкатенаций.
glib включает в себя реализацию этого,Глеб строки, который я рекомендую использовать для любого приложения, которое сильно использует строки. Это упрощает управление памятью и предотвращает переполнение буфера.
не видели никакого упоминания о функции strlcpy, strlcat, которая похожа на функции "n", за исключением также учитывает конечный 0. Оба принимают третий аргумент, указывающий максимальную длину выходного буфера,и находятся в строке.h.
пример:
char blah[]="blah";
char buffer[1024];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);
выведет "herro!!!бла"
char blah[]="blah";
char buffer[10];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);
выведет "herro!!!b " из-за ограниченного размера буфера[], без segfaulting. ^^
единственная проблема-не все платформы, похоже, включают его в свой libc (например, linux ._.), большинство всех вариантов BSD, похоже, имеют его.
в этом случае, код для обеих функций можно найти здесь и легко добавлено: strlcpy, strlcat, остальные строки.h
безопасный способ сделать это в классическом стиле 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 (с нулевым завершением) (за исключением того, что большинство этих языков будут иметь встроенную сборку мусора).