




Невозможно указать sprintf() не записывать завершающий нуль. Что вы можете сделать, так это использовать sprintf() для записи во временную строку, а затем что-то вроде strncpy() для копирования только тех байтов, которые вам нужны.
Родди: Функция snprintf всегда завершает свой вывод нулевым значением. Если вы передадите snprintf размер n, он запишет не более n-1 символов, за которыми следует завершающий символ '\ 0'.
На самом деле этот пример не добавит null: char name [9] = "QQ40dude"; беззнаковый int i0To100 = 63; _snprintf (& name [2], 2, «% d», i0To100); printf (name); // вывод: QQ63dude
@yanbellavance: Ваш пример не работает, как вы утверждаете, и печатает просто QQ6.
sprintf возвращает длину записанной строки (не включая нулевой терминал), вы можете использовать это, чтобы узнать, где был нулевой терминал, и изменить символ нулевого терминала на что-то другое (например, пробел). Это было бы более эффективно, чем использование strncpy.
unsigned int len = sprintf(str, ...);
str[len] = '<your char here>';
Вы также можете использовать строку фиксированной ширины в качестве строки формата, например:
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);
должен уступить
need 10 chars starting here: abcdefghij
Вероятно, это лучший способ сделать это.
Предотвращает ли это конечный нуль из sprintf ()? или значение my_fixed_width_string + 41 затирается нулем?
Вы не можете сделать это с помощью sprintf (), но май сможете сделать это с помощью snprintf (), в зависимости от вашей платформы.
Вам нужно знать, сколько символов вы заменяете (но, поскольку вы помещаете их в середину строки, вы, вероятно, все равно это знаете).
Это работает, потому что некоторые реализации snprintf () НЕ гарантируют, что будет записан завершающий символ - предположительно для совместимости с такими функциями, как stncpy ().
char message[32] = "Hello 123, it's good to see you.";
snprintf(&message[6],3,"Joe");
После этого «123» заменяется на «Джо».
В реализациях, где snprintf () гарантирует нулевое завершение, даже если строка усечена, это не сработает. Поэтому, если переносимость кода вызывает беспокойство, вам следует избегать этого.
Большинство Версии для Windows snprintf () демонстрируют такое поведение.
Но кажется, что MacOS и BSD (и, возможно, Linux) всегда заканчиваются нулем.
Функция snprintf всегда завершает свой вывод нулевым значением. После выполнения вышеуказанного кода сообщение содержит «Hello Jo».
@ Грег. Вы почти правы ... Я обновил ответ, чтобы отразить зависимость от реализации.
Вау, я никогда не знал, что это отличается на разных платформах, спасибо за это.
Кто-нибудь знает, что диктуют спецификации POSIX и / или C99?
Я считаю, что спецификации предписывают всегда добавлять нулевой терминатор (идея состоит в том, что строки всегда заканчиваются нулем и находятся в пределах границ, что предотвращает переполнение буфера). Однако большинство реализаций отличаются от стандарта либо отсутствием добавления \ 0, либо добавлением его после конца буфера. См. Википедию: printf.
Хотя этот ответ называет это проблемой реализации, это определенно не поведение, определяемое реализацией, как определено C поведение, определяемое реализацией §3.4.2. Это случай несоблюдения. нулевой символ указывается для добавления. Не делать этого - поведение, не соответствующее требованиям. Кроме того, это не проблема ОС, а проблема компилятора. Код может работать как следует с компилятором Windows, хотя, возможно, и не с компилятором MS.
@chux. В основном с этим согласен. Моему ответу 9 лет, и, похоже, MS наконец исправила это для соответствия. (строго говоря, проблема связана с библиотекой времени выполнения C, а не с компилятором, но они, как правило, идут рука об руку) docs.microsoft.com/en-us/cpp/c-runtime-library/reference/…
смотрите здесь: http://en.wikipedia.org/wiki/Printf
printf("%.*s", 3, "abcdef") will result in "abc" being printed
строковые версии этих функций отличаются в этом отношении от нестроковых версий. Другими словами, sprintf и snprintf всегда добавляют нулевой байт, а printf - нет, поэтому ваш пример неприменим.
Поскольку вы пишете в фиксированную область, вы можете сделать это следующим образом:
// 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).
Вот вариант для устройств с ограниченным объемом памяти. Он жертвует скоростью ради использования меньшего объема оперативной памяти. Иногда мне приходится делать это, чтобы обновить середину строки, которая выводится на ЖК-дисплей.
Идея состоит в том, что вы сначала вызываете snprintf с буфером нулевого размера, чтобы определить, какой индекс будет сбит нулевым терминатором.
Вы можете запустить приведенный ниже код здесь: https://rextester.com/AMOOC49082
#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
Или используйте memmove () или, возможно, memcpy (), а не strncpy ().