字符串和char数组如何在C中工作?

时间:2012-10-04 00:48:05

标签: c arrays string c-strings

我见过的导游似乎没有解释这一点。

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

有人可以在这里直接录制唱片吗?在最后一种情况下,使用文字,你如何处理空终止?我发现这很令人困惑。


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

3 个答案:

答案 0 :(得分:11)

  

分配的char*char[25]之间有什么区别?

malloc - ed字符串的生命周期不受其声明范围的限制。用简单的语言,您可以从函数返回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填充。

答案 1 :(得分:7)

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

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

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

  • 字符串文字的行为会有所不同,具体取决于您使用它们的方式。如果你使用它们初始化一个char数组char s[] = "String";,那么你只需要声明一个足够大的数组来完全保存该字符串(和null终止符)并将该字符串放在那里。它与声明一个char数组然后填充它一样。

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

答案 2 :(得分: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访问其内存之外没有其他办法。