char *p = "String";
这是合法的,但确实应该是:
const char *p = "String";
这样您就不会不小心尝试修改数组。
你问什么数组?任何字符串文字都对应于大小为LEN+1 的静态分配数组,其中LEN 是文字的长度。所以在这种情况下,有一个char[7] 类型的 anonymous 数组存在于程序的整个执行过程中,其中包含值
`{ 'S', 't', 'r', 'i', 'n', 'g', '\0' }`.
p 的初始化程序使其指向该数组的第一个元素,其中包含 'S'。由于数组不是通过调用malloc()(或calloc(),或realloc())分配的,您不得尝试free()它。
给定p,您不能直接确定数组的大小(因为p 指向它的第一个元素,而不是整个数组)。您可以计算strlen(p) + 1,它可能与分配的大小相同——但如果字符串文字是"foo\0bar",那么它将是8个字节长,但strlen会停在第一个空字符并返回3。因此,如果您需要能够确定数组的大小,请不要通过将其地址分配给指针来丢弃该信息。
现在,如果你改为写:
char arr[] = "String";
初始化程序会将字符串文字的内容复制到数组arr,而arr 的大小将由编译器根据初始化程序的大小确定。同样,你不能尝试在这个数组上调用free()(或者更确切地说,在指向它的第一个元素的指针上),因为它不是用malloc()分配的。但是您可以通过sizeof arr 轻松确定其大小,这将产生7。 (sizeof p 会给你一个指针的大小,而不是它指向的数组的大小。)
最后,如果你使用malloc() 来分配一个数组:
#define message "String"
char *p = malloc(sizeof message + 1);
if (p == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(p, message);
你仍然不能使用p(它只是一个指向单个字符的指针)来确定分配数组的大小——但是free() 能够弄清楚。如何?语言没有说,但任何实现都会在幕后保留额外的簿记信息,让free() 做正确的事情。
请注意,实现不一定记住您请求的大小。对malloc(7) 的调用实际上可能分配了16 个字节,而free 需要的唯一信息是基地址和实际分配的大小。
但是既然你写了对malloc的调用,如果你需要记住分配的大小,把它保存在某个地方:
// ...
const size_t allocated_bytes = sizeof message + 1;
char *p = malloc(allocated_bytes);
// ...
如果你有一个声明的数组对象,你可以使用sizeof 来确定它的大小。数组通常使用指针来操作,指针不保留数组的大小;你必须自己跟踪。 malloc() 和朋友们确实在幕后维护了一些尺寸信息,但只是为了让free() 正常工作;您(可能)自己无法访问该信息。如果您需要跟踪已分配数组的大小,则必须自己完成。