PAYATHON 2026

C 中如何逐字节打印动态分配内存?

数据小陈

结论

循环每次读取一个字节。输出看起来像更大的数,主要是因为 char 可能是有符号类型:高位为 1 的字节传给 printf 时会扩展成负的 int。另外,%2x 中的 2 表示最小字段宽度,并不固定输出宽度。读取对象表示时使用 unsigned char,再将值转成 unsigned int 传给 %02x,就能按两位十六进制显示每个字节。

const unsigned char *bytes = (const unsigned char *)vector;
printf("memory content: ");
for (size_t i = 0; i < size; i++) {
    printf("%02x ", (unsigned int)bytes[i]);
}
printf("\n");

为什么会出现 ffffffc8

原代码传给 printf 的是 char。如果实现中的 char 带符号,值大于 0x7f 的字节可能会被解释为负数,并在默认参数提升后变成负的 int。此时用 %x 这个无符号十六进制转换说明符打印,参数类型不匹配,结果可能类似 ffffffc8。具体表现取决于实现,不能据此认定读取了 4 个字节。

改用 unsigned char 后,单字节值的范围是 0 到 255。%02x 中的 0 表示用零补足宽度,2 表示最小宽度为两位。将值强转为 unsigned int,则与 %x 要求的参数类型对应。

完整示例

#include <stdio.h>
#include <stdlib.h>

 typedef struct {
    int len;
    int *vec[];
} vec_t;

int main(void) {
    size_t n = 3;
    size_t size = sizeof(vec_t) + n * sizeof(int *);
    vec_t *vector = malloc(size);
    if (vector == NULL) {
        return 1;
    }

    vector->len = (int)n;
    for (size_t i = 0; i < n; i++) {
        vector->vec[i] = NULL;
    }

    const unsigned char *bytes = (const unsigned char *)vector;
    printf("memory content: ");
    for (size_t i = 0; i < size; i++) {
        printf("%02x ", (unsigned int)bytes[i]);
    }
    printf("\n");

    free(vector);
    return 0;
}

循环每次访问 bytes[i],也就是每次处理一个字节。size 可能因平台而异,因为 int 和指针的大小,以及结构体的对齐规则,都由实现决定。仅凭这段代码,不能断定分配大小一定是 16 字节。也可以用柔性数组成员的元素类型来写分配大小:

size_t size = sizeof(vec_t) + n * sizeof(vector->vec[0]);

查看结果时的注意事项

原问题的补充说明提到,完整项目中指针实际上没有按预期赋值为 NULL。如果指针未初始化,它的值是不确定的,因此打印出的字节不会呈现预期的空指针内容。示例代码虽然显式赋值了 NULL,但 C 标准并未要求空指针的对象表示一定由全零位组成。

结构体也可能包含填充字节。这些字节不代表成员值,也不能假定它们固定为零。逐字节查看适合调试对象表示,但不能据此推断跨平台的内存布局。

备注:内容仅供参考。