Использование 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 (с нулевым завершением) (за исключением того, что большинство этих языков будут иметь встроенную сборку мусора).