您将需要在同一内存块中为长度和字符串分配空间。这可能是您对结构的预期目的,但您只为指向字符串的指针保留了空间。
必须分配空间来包含字符串的字符。
例如:
typedef struct
{
int num_chars;
char string[];
} my_string_t;
my_string_t * alloc_my_string(char *src)
{
my_string_t * p = NULL;
int N_chars = strlen(src) + 1;
p = malloc( N_chars + sizeof(my_string_t));
if (p)
{
p->num_chars = N_chars;
strcpy(p->string, src);
}
return p;
}
在我的示例中,要访问指向字符串的指针,您需要寻址string
的成员my_string_t
:
my_string_t * p = alloc_my_string("hello free store.");
printf("String of %d bytes is '%s'\n", p->num_chars, p->string);
请注意,您正在获取字符串的指针,这是分配空间来存储字符的结果。您分配的资源是字符的存储,获得的指针是对分配的存储的引用。
在我的示例中,分配的内存按顺序排列如下:
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 00 | 00 | 00 | 11 | 'h'| 'e'| 'l'| 'l'| 'o'| 20 | 'f'| 'r'| 'e'| 'e'| 20 | 's'| 't'| 'o'| 'r'| 'e'| '.'| 00 |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
^^ ^
|| |
p| |
p->num_chars p->string
请注意,值p->string
不存储在分配的内存中,它是从分配的内存开头算起的四个字节,紧跟在(假定为 32 位,四字节)整数之后。
您的编译器可能要求您将灵活的 C 数组声明为:
typedef struct
{
int num_chars;
char string[0];
} my_string_t;
但缺少零的版本据说是符合 C99 标准的。
您可以在没有数组成员的情况下完成等效的操作,如下所示:
typedef struct
{
int num_chars;
} mystr2;
char * str_of_mystr2(mystr2 * ms)
{
return (char *)(ms + 1);
}
mystr2 * alloc_mystr2(char *src)
{
mystr2* p = NULL;
size_t N_chars = strlen(src) + 1;
if (N_chars num_chars = (int)N_chars;
strcpy(str_of_mystr2(p), src);
}
return p;
}
printf("String of %d bytes is '%s'\n", p->num_chars, str_of_mystr2 (p));
在第二个示例中,该值相当于p->string
计算公式为str_of_mystr2()
。它的值与第一个示例大致相同,具体取决于编译器设置如何打包结构的末尾。
虽然有些人建议跟踪长度size_t
我会查阅多布博士的一些旧文章来了解我为什么不同意。支持大于 INT_MAX 的值对于程序的正确性来说价值值得怀疑。通过使用 int,你可以写assert(p->num_chars >= 0);
并进行测试。对于无符号,您可以编写类似的等效测试assert(p->num_chars < UINT_MAX / 2);
只要您编写的代码包含对运行时数据的检查,使用签名类型就会很有用。
另一方面,如果您正在编写一个处理超过 UINT_MAX / 2 个字符的字符串的库,我向您致敬。