C格式说明符大小

时间:2019-01-09 00:02:01

标签: c

如何访问字符数组中的整数值?

char a = 'A';
int b = 90;
char * c = "A String";
snprintf(output_buffer, 1024, "%c%d%s, a,b,c);`

%d格式说明符(假设为4?)将占用此字符数组多少个字节,并且如何访问整数值b?

我尝试过:

int x = *((int *) &output_buffer[1]

没有成功。

short x; 
sscanf(&output_buffer[1], "%d", &x);
printf("%d\n",x);`

char *buffer; 
sscanf(&output_buffer[3], "%s", buffer);
printf("%s\n",buffer);`

3 个答案:

答案 0 :(得分:3)

要回答您的原始问题“ "%d"需要多少个字符?”,可以通过将缓冲区指定为snprintf和字符数来对NULL使用技巧为0,然后使用"%d"格式字符串和变量bsnprintf将返回转换所需的位数,例如

    req = snprintf (NULL, 0, "%d", b);
    printf ("required digits: %d\n", req);

将输出"required digits: 2"。 (“如果有足够的空间,将被写入最终字符串的字符数(不包括终止空字节)。” )在为{{1}动态分配存储空间时,这很有用}。实际上,您只需提供完整的 format字符串,所有变量和buffer就会返回所需的字符总数(为 nul添加snprintf -终止字符)

在最后的几条评论中,我认为您想从+1内部将90读回到int中。这很简单。

对于一般情况,您不只是尝试使用buffer中的第二个字符(例如buffer)进行转换,而只是想从缓冲区中的第一个字符开始并向前扫描直到找到第一个数字。 (如果您有明确的带符号的值,也可以检查buffer[1]

要在'+/-'中向前扫描以查找第一个数字,请遍历buffer中的字符(使用索引,例如buffer,或使用指针,例如{{ 1}},然后递增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,则可以将它们添加到相同的位置以'-'为条件)

使用/输出示例

'+'

在最后一条评论后想要'a,b&c`返回

您已经拥有从缓冲区取回isdigit()所需的一切。由于您使用了$ ./bin/snprintf_string A90A String int read from buffer: 90 ,并且a, b & c会指向转换后的最后一位数字之后的下一个字符,因此您可以通过简单地输出以下值来从缓冲区中返回strtol,例如

endptr

修改后的示例用法/输出

a, b & c

仔细检查一下,如果还有其他问题,请告诉我。

答案 1 :(得分:2)

有一个%n修饰符,可将实际写入的字节数存储到int中:

int main(int argc, char *argv[])
{
    int p0;
    int p1;
    char    buf[128];

    sprintf(buf, "%c%n%d%n%s", argv[0][0], &p0, atoi(argv[1]), &p1, argv[1]);
    printf("'%s' -> %d, %d\n", buf, p0, p1);
}

但是这个修饰符被认为是危险的;一些实现要求格式字符串位于只读存储器中。

为使最后一句话更清楚,举一个例子:

#include <stdio.h>

int main(void)
{
        char    fmt[] = "%n";
        int     pos;

        printf("%n", &pos);
        printf("ok\n");

        printf(fmt, &pos);
        printf("ok\n");
}

然后

$ gcc x.c -D_FORTIFY_SOURCE=2 -O2
$ ./a.out 
ok
*** %n in writable segment detected ***
Aborted (core dumped)

答案 2 :(得分:0)

在您的示例中,假设您要查询的字符数组为output_buffer,并且在体系结构中char的大小为1个字节,则%d将占用2个字节,每个int的位数(b = 90) 。要获取该值,请使用:

int x; 
sscanf(&output_buffer[1], "%d", &x);
char buffer[255]; 
sscanf(&output_buffer[3], "%[^\n]", buffer);

请检查缓冲区的大小,以避免溢出