8

我见过的任何指南似乎都没有很好地解释这一点。

我的意思是,您可以为 a 分配内存char*,或者char[25]改为写入?有什么不同?然后是文字,不能被操纵?如果要将固定字符串分配给变量怎么办?就像,stringVariable = "thisIsALiteral"那么你之后如何操纵它?

有人可以在这里直接记录吗?在最后一种情况下,对于文字,你如何处理空终止?我觉得这很令人困惑。


编辑:真正的问题似乎是,据我了解,您必须兼顾这些不同的结构才能完成甚至简单的事情。例如,onlychar *可以作为参数或返回值传递,但只能char[]分配文字和修改。我觉得很明显,我们经常/总是需要能够同时做到这两点,这就是我的陷阱所在。

4

3 回答 3

13

char*分配的和有什么区别char[25]

-ed 字符串的生命周期malloc不受其声明范围的限制。用简单的语言,您可以malloc从函数中返回 -ed 字符串;你不能对自动存储char[25]中的分配做同样的事情,因为它的内存将在从函数返回时被回收。

文字可以被操纵吗?

字符串文字不能就地操作,因为它们是在只读存储中分配的。您需要将它们复制到可修改的空间中,例如静态、自动或动态空间,以便对其进行操作。这是无法做到的:

char *str = "hello";
str[0] = 'H'; // <<== WRONG! This is undefined behavior.

这将起作用:

char str[] = "hello";
str[0] = 'H'; // <<=== This is OK

这也有效:

char *str = malloc(6);
strcpy(str, "hello");
str[0] = 'H'; // <<=== This is OK too

你如何处理字符串文字的空终止?

C 编译器会为您处理空终止:所有字符串文字的末尾都有一个额外的字符,用\0.

于 2012-10-04T00:54:42.977 回答
8

您的问题涉及 C 中的三种不同构造:char 数组、在堆上分配的 char 指针和字符串文字。这些都是不同的,是微妙的方式。

  • Char 数组,您通过char foo[25]在函数内部声明获得的内存是在堆栈上分配的,它只存在于您声明它的范围内,但正好为您分配了 25 个字节。您可以在这些字节中存储您想要的任何内容,但如果您想要一个字符串,请不要忘记使用最后一个字节来终止它。

  • 用 定义的字符指针char *bar仅保存指向某些未分配内存的指针。要使用它们,您需要将它们指向某个东西,或者像以前一样的数组 ( bar = foo) 或分配空间bar = malloc(sizeof(char) * 25);。如果你做后者,你最终应该释放空间。

  • 字符串文字的行为取决于您如何使用它们。如果您使用它们来初始化 char 数组char s[] = "String";,那么您只需声明一个足够大的数组以准确保存该字符串(和空终止符)并将该字符串放在那里。这与声明一个 char 数组然后填充它是一样的。

    另一方面,如果您将字符串文字分配给 achar *那么指针指向您不应该修改的内存。尝试修改它可能会或可能不会崩溃,并导致未定义的行为,这意味着您不应该这样做。

于 2012-10-04T01:00:59.580 回答
5

由于已经回答了其他方面,我只会添加问题“如果您想要使用 char * 传递函数的灵活性但 char [] 的可修改性怎么办

您可以分配一个数组并将相同的数组传递给一个函数作为 char *。这称为按引用传递,内部仅传递实际数组的地址(准确地说是第一个元素的地址),而不是复制整个。另一个影响是函数内部所做的任何更改都会修改原始数组。

void fun(char *a) {
   a[0] = 'y'; // changes hello to yello
}

main() {
   char arr[6] = "hello"; // Note that its not char * arr
   fun(arr); // arr now contains yello
}

对于使用 malloc 分配的数组也可以这样做

char * arr = malloc(6);
strcpy(arr, "hello");

fun(arr); // note that fun remains same.

稍后您可以释放 malloc 内存

free(arr);

char * a, 只是一个可以存储地址的指针,它可能是单个变量,也可能是数组的第一个元素。请注意,我们必须在实际使用它之前分配给这个指针。

与 char arr[SIZE] 相反,它在堆栈上创建一个数组,即它还分配 SIZE 个字节。因此,您可以直接访问 arr[3](假设 3 小于 SIZE)而不会出现任何问题。

现在允许将任何地址分配给 a是有意义的,但不允许将其分配给 arr,因为除了使用 arr 访问其内存之外别无他法。

于 2012-10-04T05:18:11.657 回答