В ответ на ваш первоначальный вопрос «сколько символов займет "%d"
?», Вы можете использовать трюк с snprintf
, указав буфер как NULL
и количество символов как 0
, и затем, используя строку формата "%d"
и переменную b
, snprintf
вернет количество цифр, которое потребуется для преобразования, например
req = snprintf (NULL, 0, "%d", b);
printf ("required digits: %d\n", req);
Который выдаст "required digits: 2"
. ( "количество символов (исключая завершающий нулевой байт), которое было бы записано в конечную строку, если бы было достаточно места." ) Что полезно при динамическом выделении памяти для buffer
. Фактически, вы просто предоставляете свою полную строку формата и все переменные, и snprintf
вернет общее количество необходимых символов (к которому вы добавите +1
для nul-terminating символы)
Из последних нескольких комментариев, я так понимаю, вы хотите прочитать 90
обратно в int
из buffer
. Это достаточно просто сделать.
Вместо того, чтобы просто пытаться преобразовать, используя 2-й символ в buffer
(например, buffer[1]
), для общего случая вы просто хотите начать с 1-го символа в буфере и сканировать вперед, пока не найдете первую цифру , (Вы также можете проверить '+/-'
, если у вас есть явные значения со знаком).
Чтобы просмотреть вперед в buffer
, чтобы найти первую цифру, вы перебираете символы в buffer
(либо используя индексы, например, buffer[x]
, либо используя указатель, например, char *p = buffer;
и увеличивая p++
) и проверьте, является ли каждый символ цифрой. Хотя вы можете просто использовать if ('0' <= *p && *p <= '9')
, заголовок ctype.h
предоставляет макрос isdigit()
, который делает это довольно легко. Чтобы найти первую цифру, вы можете сделать что-то вроде:
#include <ctype.h> /* for isdigit */
...
char buffer[MAXC] = "", /* buffer to hold a, b, c */
*p = buffer;
...
while (*p && !isdigit(*p)) /* scan forward in buffer to 1st digit */
p++;
Как только вы нашли свою первую цифру, вы преобразуете последовательность цифр в значение long
, используя strtol
(что обеспечивает полную проверку ошибок), например,
#include <stdlib.h>
#include <errno.h> /* for errno */
#include <limits.h> /* for INT_MIN/INT_MAX */
...
char *endptr; /* end pointer to use with strtol */
long tmp; /* long value for return of strtol */
...
errno = 0; /* reset errno - to check after strtol */
tmp = strtol (p, &endptr, 0); /* save conversion result in tmp */
( примечание: избегать atoi()
- обеспечивает ноль проверка ошибок преобразования)
Теперь tmp
содержит возврат strtol
, который будет содержать преобразование в long
цифр, найденных в buffer
, начиная с p
(в случае успеха). Но прежде чем вы сможете использовать значение, возвращаемое как int
, вы должны проверить , что цифры были преобразованы, что при преобразовании не возникло ошибок и что значение в tmp
находится в диапазоне int
. Вы можете сделать все с помощью нескольких условных проверок. Если все ваши проверки выполнены, вы можете присвоить значение в tmp
целому числу (с соответствующим приведением) и быть уверенным в своем конечном значении, например,
if (p == endptr) /* check if pointer == end pointer */
fputs ("error: no digits converted.\n", stderr);
else if (errno) /* if errno set, over/underflow occurred */
fputs ("error: invalid conversion to long.\n", stderr);
else if (tmp < INT_MIN || INT_MAX < tmp) /* will fit in int? */
fputs ("error: value exceeds range of int.\n", stderr);
else { /* good value, assign to b_from_buf, output */
b_from_buf = (int)tmp;
printf ("\nint read from buffer: %d\n", b_from_buf);
}
Соединяя ваш пример (включая проверку вашей первоначальной записи в buffer
с помощью snprintf
, вы могли бы сделать что-то похожее на следующее):
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h> /* for isdigit */
#include <errno.h> /* for errno */
#include <limits.h> /* for INT_MIN/INT_MAX */
#define MAXC 1024
int main (void) {
char a = 'A',
*c = "A String",
buffer[MAXC] = "", /* buffer to hold a, b, c */
*p = buffer, /* pointer to buffer */
*endptr; /* end pointer to use with strtol */
int b = 90,
b_from_buf, /* int to read from filled buffer */
rtn; /* return for snprintf to validate */
long tmp; /* long value for return of strtol */
rtn = snprintf (buffer, MAXC, "%c%d%s", a, b, c);
if (rtn < 0) { /* if < 0, error occurred */
fputs ("error: writing to buffer.\n", stderr);
return 1;
}
else if (rtn >= MAXC) /* if > size, truncation occurred */
fputs ("warning: buffer contains truncated string.\n", stderr);
printf ("%s\n", buffer); /* output buffer */
while (*p && !isdigit(*p)) /* scan forward in buffer to 1st digit */
p++;
errno = 0; /* reset errno - to check after strtol */
tmp = strtol (p, &endptr, 0); /* save conversion result in tmp */
if (p == endptr) /* check if pointer == end pointer */
fputs ("error: no digits converted.\n", stderr);
else if (errno) /* if errno set, over/underflow occurred */
fputs ("error: invalid conversion to long.\n", stderr);
else if (tmp < INT_MIN || INT_MAX < tmp) /* will fit in int? */
fputs ("error: value exceeds range of int.\n", stderr);
else { /* good value, assign to b_from_buf, output */
b_from_buf = (int)tmp;
printf ("\nint read from buffer: %d\n", b_from_buf);
}
}
( примечание: если значение в buffer
может иметь явный знак перед ним, например, '-'
или '+'
, то вы добавляете их к тому же условному выражению с помощью isdigit()
)
Пример использования / Вывод
$ ./bin/snprintf_string
A90A String
int read from buffer: 90
После последнего комментария Желая 'a, b & c` Назад
У вас уже есть все, что нужно, чтобы получить a, b & c
из буфера. Поскольку вы использовали strtol
и endptr
будут указывать на следующий символ после последней преобразованной цифры, вы можете получить a, b & c
обратно из буфера, просто выводя значения, например,
else { /* good value, assign to b_from_buf, output */
b_from_buf = (int)tmp;
printf ("\n(a) 1st char in buffer : %c\n"
"(b) int read from buffer : %d\n"
"(c) remaining chars in buffer : %s\n",
*buffer, b_from_buf, endptr);
}
Модифицированный пример Использование / Вывод
$ ./bin/snprintf_string
A90A String
(a) 1st char in buffer : A
(b) int read from buffer : 90
(c) remaining chars in buffer : A String
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.