Есть ли способ использовать функцию C sprintf() без добавления символа «\ 0» в конце ее вывода? Мне нужно написать форматированный текст в середине строки фиксированной ширины.
sprintf() без нулевого пробела в конце в C
Ответы (8)
Невозможно указать sprintf()
не записывать конечный нуль. Что вы можете сделать, так это использовать sprintf()
для записи во временную строку, а затем что-то вроде strncpy()
для копирования только тех байтов, которые вам нужны.
QQ6
.
- person Greg Hewgill; 23.02.2015
sprintf возвращает длину написанной строки (не включая нулевой терминал), вы можете использовать это, чтобы узнать, где был нулевой терминал, и изменить символ нулевого терминала на что-то другое (например, пробел). Это было бы более эффективно, чем использование strncpy.
unsigned int len = sprintf(str, ...);
str[len] = '<your char here>';
Вы не можете сделать это с помощью sprintf(), но вы можете сделать это с помощью snprintf(), в зависимости от вашей платформы.
Вам нужно знать, сколько символов вы заменяете (но поскольку вы помещаете их в середину строки, вы, вероятно, все равно это знаете).
Это работает, потому что некоторые реализации snprintf() НЕ гарантируют запись завершающего символа - предположительно для совместимости с такими функциями, как stncpy().
char message[32] = "Hello 123, it's good to see you.";
snprintf(&message[6],3,"Joe");
После этого «123» заменяется на «Джо».
В реализациях, где snprintf() гарантирует нулевое завершение, даже если строка усечена, это не сработает. Поэтому, если переносимость кода вызывает беспокойство, вам следует избегать этого.
Большинство версий snprintf() для Windows демонстрируют такое поведение.
Но MacOS и BSD (и, возможно, Linux ), кажется, всегда заканчивается нулем.
Вы также можете использовать строку фиксированной ширины в качестве строки формата, например:
char my_fixed_width_string_format[] = "need 10 chars starting here: %10s";
char my_fixed_width_string[40];
char string_to_print[] = "abcdefghijklmnop";
sprintf(my_fixed_width_string, my_fixed_width_string_format, string_to_print;
printf(my_fixed_width_string);
должен дать
нужно 10 символов, начиная здесь: abcdefghij
Поскольку вы пишете в фиксированную область, вы можете сделать это следующим образом:
// pointer to fixed area we want to write to
char* s;
// number of bytes needed, not including the null
int r = snprintf(0, 0, <your va_args here>);
// char following the last char we will write - null goes here
char c = s[r + 1];
// do the formatted write
snprintf(s, r + 1, <your_va_args here>);
// replace what was overwritten
s[r + 1] = c;
На самом деле этот пример не добавит null, если вы используете snprintf:
char name[9] = "QQ40dude";
unsigned int i0To100 = 63;
_snprintf(&name[2],2,"%d",i0To100);
printf(name);// output will be: QQ63dude
QQ6
с POSIX snprintf(3)
.
- person nodakai; 26.05.2015
Вот вариант для устройств с ограниченным объемом памяти. Он жертвует скоростью для использования меньшего количества оперативной памяти. Иногда мне приходится делать это, чтобы обновить середину строки, которая печатается на ЖК-дисплее.
Идея состоит в том, что вы сначала вызываете snprintf с буфером нулевого размера, чтобы определить, какой индекс будет затерт нулевым ограничителем.
Вы можете запустить следующий код здесь: https://rextester.com/AMOC49082
#include <stdio.h>
#include <string.h>
int main(void)
{
char buf[100] = { 'a', 'b', 'c', 'd', 'e' };
const size_t buf_size = sizeof(buf);
const int i = 123;
int result = snprintf(buf, 0, "%i", i);
if (result < 0)
{
printf("snprintf error: %i\n", result);
return -1;
}
int clobbered_index = result; //this index will get the null term written into it
if (result >= buf_size)
{
printf("buffer not large enough. required %i chars\n", result + 1);
return -1;
}
char temp_char = buf[clobbered_index];
result = snprintf(buf, buf_size, "%i", i); //add result error checking here to catch future mistakes
buf[clobbered_index] = temp_char;
printf("buf:%s\n", buf);
return 0;
}
Печатает buf:123de
посмотрите здесь: http://en.wikipedia.org/wiki/Printf
printf("%.*s", 3, "abcdef") приведет к печати "abc"