Используя strcat в C

Хорошо, таким образом, у меня есть следующий Код, который добавляет строку другому в C#, обратите внимание, что это - Просто пример, так предоставление альтернативных строковых методов конкатенации в C# не является nessesary, это должно только упростить пример.

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 и просто сделать это тот же способ, которым я сделал в C#?

11
задан Joachim Sauer 7 January 2009 в 10:48
поделиться

7 ответов

Изменение

char *message = "\n\nHTTP/1.1 ";

кому:

char message[1024];  
strcpy(message,"\n\nHTTP/1.1 ");

и необходимо быть в порядке до общей длины сообщения 1 023.

Править: (согласно комментарию mjy). Используя strcat этим способом отличный способ получения переполнения буфера. Вы могли с готовностью записать небольшую функцию, которая проверяет размер буфера и продолжительность входящего строкового дополнения для преодоления этого или перевыделения использования на динамическом буфере. IMO, бремя находится на программисте для проверки корректных буферных размеров, где они используются, как с sprintfs и другими функциями струн до. Я предполагаю, что C используется по C++ по причинам производительности, и следовательно STL не является опцией.

Править: Согласно запросу из комментария Filip, простой strcat реализации на основе буфера символа фиксированного размера:

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++)

Приложение (Мир):

Хорошо, так как Вы на самом деле не объяснили, почему необходимо было создать message[1024], здесь это.

С символом *x = "привет", фактические байты ('h', 'e', 'l', 'l', 'o', 0) (пустой указатель на конце) хранятся в области памяти, отдельной от переменных (и вполне возможно только для чтения), и переменная x установлен указать на него. После пустого указателя существует, вероятно, что-то еще очень важное. Таким образом, Вы не можете добавить к этому вообще.

С char x[1024]; strcpy(x,"hello");, Вы сначала выделяете 1K om память, которая полностью выделена x. Затем Вы копируете "привет" в него и все еще оставляете довольно мало пространства в конце для добавления большего количества строк. Вы не попадете в беду, пока Вы не добавите больше, чем позволенный 1K-odd.

Приложение конца (Мир):

19
ответ дан 3 December 2019 в 02:02
поделиться

Интересно, почему никто не упомянул 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() буфер, сделано с помощью него!

8
ответ дан 3 December 2019 в 02:02
поделиться

Запустите с использования более безопасного strncat функция. В целом всегда используйте более безопасные функции 'n', которые не переполнятся, если размер строки будет больше, чем определенный размер.

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

6
ответ дан 3 December 2019 в 02:02
поделиться

обменивайтесь сообщениями указывает на символьную константу [], что Вы не можете записать в, все же это точно, где strcat пишет. Вам нужен к malloc () достаточно большой буфер.

2
ответ дан 3 December 2019 в 02:02
поделиться

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

-2
ответ дан 3 December 2019 в 02:02
поделиться

Не видели упоминания о 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!!! вздор"

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, остальная часть string.h

1
ответ дан 3 December 2019 в 02:02
поделиться

Как сказано ранее, необходимо записать в достаточно большой буфер. К сожалению, выполнение так является большой дополнительной работой. Большинство приложений C, которые имеют дело со строками, использует динамично строковый буфер изменяемого размера для того, чтобы сделать конкатенации.

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

1
ответ дан 3 December 2019 в 02:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: