Создайте строку, содержащую в середине

#c #string

Вопрос:

У меня есть:

 char *var1 = "foo";
char *var2 = "bar";
 

и я хочу создать эту строку: «foobar»

Как я могу это сделать? Я пробовал это, но, конечно, это не работает:

 sprintf(buffer, "%s%s", var1, var2);
 

Комментарии:

1. sprintf(buffer, "%s%c%s", var1, 0, var2); сделал бы это.

2. Щенок, «строка , содержащая в середине», не является строкой для начала… строки могут заканчиваться только на , любая функция, которая имеет дело со строками в C, остановится на . Не уверен, чего вы здесь пытаетесь достичь.

3. Это выглядит как классический пример проблемы X-Y. Чего вы на самом деле пытались достичь, когда решили, что необходимо пересмотреть определение C того, что представляет собой «строка»?

4. У вас не может быть строки с буквой а '' посередине. Строка по определению заканчивается первой '' . Вы, конечно, можете иметь массив символов, содержащий "foobar" -но каждая строковая функция будет обрабатывать свое содержимое как строку "foo" . Не пытайтесь переопределить, что такое «строка»; просто смиритесь с тем фактом, что у вас есть массив символов, содержимое которого не является строкой. Вероятно, вам придется отслеживать, сколько символов имеет значение, и использовать mem*() функции, а не str*() .

Ответ №1:

У вас здесь две проблемы:

  1. Положить (он же нулевой) в середине любая строка является законным, но это также означает, что все API-интерфейсы c строка будет рассматривать строку как закончить пораньше; все строки в стиле C оканчивается на нуль, и нет никакого способа, чтобы сказать, разница между новым нул вы добавили, и «Реал нуль», потому что он должен предположить, что первый нуль встречается в конце строки (читать дальше мог читать неинициализированной памяти или чтение за концом массива целиком, вызывая неопределенное поведение). Поэтому, даже если вы добьетесь успеха, API C, которые работают со строками, никогда не увидят bar . Вам нужно будет отслеживать, как долго была «настоящая» строка, и использовать нестроковые API для работы с ней ( sprintf возвращает, сколько символов она напечатала, поэтому вы не работаете полностью вслепую).
  2. Попытка поместить в саму строку формата означает, что sprintf , по его мнению, строка формата заканчивается там; с его точки зрения, "%s%s" это точно то же самое "%s" , что буквально не может отличить их друг от друга.

Вы можете обойти проблему № 2, вставив NUL с кодом формата, который вставляет один char (где NUL не является специальным), например:

 sprintf(buffer, "%s%c%s", var1, '', var2);
 

но даже когда вы закончите, выполнение printf("%s", buffer); будет отображаться только foo (потому что встроенный NUL-это место, где сканирование останавливается). Данные есть, и к ним можно получить доступ, только не с помощью API-интерфейсов C-строк:

 #include <stdio.h>

int main(int argc, char **argv) {
    char *var1 = "foo";
    char *var2 = "bar";
    char buffer[10] = "0123456789";
    sprintf(buffer, "%s%c%s", var1, '', var2);

    for (int i = 0; i < sizeof(buffer);   i) {
        printf("'%c': %hhdn", buffer[i], buffer[i]);
    }
    return 0;
}
 

Попробуйте это онлайн!

какие результаты:

 'f': 102
'o': 111
'o': 111
'': 0
'b': 98
'a': 97
'r': 114
'': 0
'8': 56
'9': 57
 

Пустые кавычки содержат нулевой байт, если вы посмотрите на ссылку TIO, но, о чудо, мой браузер останавливает копирование/вставку в нулевом байте (да, C-строковые API), поэтому я не могу скопировать его здесь.

Комментарии:

1. С sprintf(buffer, "%s%c%s", var1, '', var2); , используйте возвращаемое значение from sprintf() для управления следующим for циклом. n = sprintf(....); for (int i = 0; i < n; i) {

2. @chux-ReinstateMonica: Да, я упомянул, что возвращаемое значение является полезным в конце проблему #1, я намеренно не использовал его в пример, потому что я хотел показать, как изменился код (используя %c ), на деле печатать все, а как там на самом деле два NUL с производства, а также показывает, какие значения есть заменил в инициализации массива, которые первоначально были персонажами из 0 до 9 .

Ответ №2:

Это довольно распространенная проблема при работе с двоичными данными.

Если вы хотите манипулировать двоичными данными, не используйте строковые инструменты strcat, strcpy и т. Д., Потому что они используют нулевое завершение для определения длины строки.

Вместо этого используйте процедуру библиотеки memcpy, которая требует, чтобы вы указали длину. Следите за каждой двоичной строкой в виде указателя и длины.

 char *var1="foo";
unsigned len1 = 3;
char *var2="bar";
unsigned len2 = 3;

/* write var1 and var2 to buffer with null-separation */
/* assuming buffer is large enough */
char buffer[10];
unsigned len_buffer = 0;

/* write var1 to start of buffer */
memcpy(buffer, var1, len1);
len_buffer = len1;

/* append null */
buffer[len_buffer  ] = '';

/* append var2 */
memcpy(buffer len_buffer, var2, len2);
len_buffer  = len2;
 

Ответ №3:

Не особенно быстро или коротко, но это должно сделать свою работу

 strcpy (buffer, var1);
strcat (buffer strlen(var1) 1, var2);