char *和char[]之间的区别

3
我已经阅读了很多关于这方面的帖子和问题,并阅读了很多答案,但仍然难以理解它们之间的区别以及何时应该使用哪个?
我认为当您需要存储数据且不知道其大小因为它是动态的时,应该使用char*。此外,我不确定是否正确,但从我所了解的来看,如果您声明一个char*并将其赋值为文字文本,例如: char *ch = "hi"; 它是一个常量,您无法更改它,如果尝试更改它,则只会将ch指向另一个分配的内存空间,其中包含新字符串? 如果按照以下方式编写: char ch = malloc(20); 那么您可以更改值 并且如果您这样做: char ch[] = "hi"; char pch = ch; 您也可以更改值,因为您指向数组,数组指向ch[0]?
所有加粗的内容都是我通过阅读得出的理解,虽然我可能对我刚才说的大部分内容都错误,这就是为什么我需要一个真正好的简单解释,以便我最终能够理解它们之间的区别以及何时应该使用哪个。
编辑:
#include <stdio.h>

main()
{
    char ch[] = "Hello";
    char *p1 = ch;
    char *p2 = p1;
    char *p3 = *p1;
    printf("ch : %s\n", ch);
    printf("p1 address [%d] value is %s\n", p1, *p1);
    printf("p2 address [%d] value is %s\n", p2, *p2);
    printf("p3 address [%d] value is %s\n", p3, *p3);
    return 0;
}

阅读comp.lang.c FAQ的第6节。 - Keith Thompson
1个回答

24

最直接的答案是:

这里的区别在于

char *s = "Hello world";

将“Hello world”放在只读内存中,并使 s 成为指向该内存的指针,这样对该内存进行任何写操作都会非法。在执行此操作时:

char s[] = "Hello world";

将字面字符串放入只读内存,并将字符串复制到新分配的堆栈内存中。因此使

s[0] = 'J';

更详细的解释会包括存储内存的段以及分配多少内存:

Example:                       Allocation Type:     Read/Write:    Storage Location:   Memory Used (Bytes):
===========================================================================================================
const char* str = "Stack";     Static               Read-only      Code segment        6 (5 chars plus '\0')
char* str = "Stack";           Static               Read-only      Code segment        6 (5 chars plus '\0')
char* str = malloc(...);       Dynamic              Read-write     Heap                Amount passed to malloc
char str[] = "Stack";          Static               Read-write     Stack               6 (5 chars plus '\0')
char strGlobal[10] = "Global"; Static               Read-write     Data Segment (R/W)  10

参考文献


  1. C语言中char s[]和char *s的区别是什么?,访问日期2014-09-03,<https://dev59.com/NXI-5IYBdhLWcg3wu7FU>
  2. 已声明字符串和已分配字符串之间的区别,访问日期2014-09-03,<https://dev59.com/AnDYa4cB1Zd3GeqPGPhV>

编辑


针对问题中的编辑和相关评论,我已在您的解决方案中添加了注释:

#include <stdio.h>

int main() {
   char ch[] = "Hello"; /* OK; Creating an array of 6 bytes to store
                         * 'H', 'e', 'l', 'l', 'o', '\0'
                         */
   char *p1 = ch;       /* OK; Creating a pointer that points to the
                         * "Hello" string.
                         */
   char *p2 = p1;       /* OK; Creating a second pointer that also
                         * points to the "Hello" string.
                         */
   char *p3 = *p1;      /* BAD; You are assigning an actual character
                         * (*p1) to a pointer-to-char variable (p3);
                         * It might be more intuitive if written in
                         * 2 lines:
                         * char* p3;
                         * p3 = *p1; //BAD
                         */
   printf("ch : %s\n", ch);   /* OK */
   printf("p1 address [%d] value is %s\n", p1, *p1);  /* Bad format specifiers */
   printf("p2 address [%d] value is %s\n", p2, *p2);  /* Bad format specifiers */
   printf("p3 address [%d] value is %s\n", p3, *p3);  /* Bad format specifiers */
   return 0;
}

因此,有三个主要的错误。

  1. 您正在将char值分配给pointer-to-char变量。您的编译器应该警告您。( char *p3 = *p1)。
  2. 根据您的编译器,您可能必须使用指针%p格式说明符来打印地址,而不是%d(整数)格式说明符。
  3. 您正在使用%s说明符与char数据类型一起使用(即:printf("%s", 'c')是错误的)。如果要打印单个字符,则使用%c格式说明符,并且匹配的参数应该是一个字符(即:'c'、char b等)。如果要打印整个字符串,则使用%s格式说明符,并且参数是指向char的指针。

示例


#include <stdio.h>

int main(void) {
   char c = 'H';                    // A character
   char* pC = &c;                   // A pointer to a single character; IS NOT A STRING
   char cArray[] = { 'H', 'e', 'l', 'l', 'o' };   // An array of characters; IS NOT A STRING
   char cString[] = { 'H', 'e', 'l', 'l', 'o', '\0' };   // An array of characters with a trailing NULL charcter; THIS IS A C-STYLE STRING
   // You could also replace the '\0' with 0 or NULL, ie:
   //char cString[] = { 'H', 'e', 'l', 'l', 'o', (char)0 };
   //char cString[] = { 'H', 'e', 'l', 'l', 'o', NULL };
   const char* myString = "Hello world!"; // A C-style string; the '\0' is added automatically for you

   printf("%s\n", myString);        // OK; Prints a string stored in a variable
   printf("%s\n", "Ducks rock!");   // OK; Prints a string LITERAL; Notice the use of DOUBLE quotes, " "
   printf("%s\n", cString);         // OK; Prints a string stored in a variable

   printf("%c\n", c);               // OK; Prints a character
   printf("%c\n", *pC);             // OK; Prints a character stored in the location that pC points to
   printf("%c\n", 'J');             // OK; Prints a character LITERAL; Notice the use of SINGLE quotes, ' '

   /* The following are wrong, and your compiler should be spitting out warnings or even not allowing the
    * code to compile. They will almost certainly cause a segmentation fault. Uncomment them if you
    * want to see for yourself by removing the "#if 0" and "#endif" statements.
    */
#if 0
   printf("%s\n", c);               // WRONG; Is attempting to print a character as a string, similar
                                    // to what you are doing.
   printf("%s\n", *pC);             // WRONG; Is attempting to print a character as a string. This is
                                    // EXACTLY what you are doing.
   printf("%s\n", cArray);          // WRONG; cArray is a character ARRAY, not a C-style string, which is just
                                    // a character array with the '\0' character at the end; printf
                                    // will continue printing whatever follows the end of the string (ie:
                                    // random memory, junk, etc) until it encounters a zero stored in memory.
#endif
   return 0;
}

代码清单 - 建议解决方案


#include <stdio.h>

int main() {
   char ch[] = "Hello"; /* OK; Creating an array of 6 bytes to store
                         * 'H', 'e', 'l', 'l', 'o', '\0'
                         */
   char *p1 = ch;       /* OK; Creating a pointer that points to the
                         * "Hello" string.
                         */
   char *p2 = p1;       /* OK; Creating a second pointer that also
                         * points to the "Hello" string.
                         */
   char *p3 = p1;       /* OK; Assigning a pointer-to-char to a 
                         * pointer-to-char variables.
                         */
   printf("ch : %s\n", ch);   /* OK */
   printf("p1 address [%p] value is %s\n", p1, p1);  /* Fixed format specifiers */
   printf("p2 address [%p] value is %s\n", p2, p2);  /* Fixed format specifiers */
   printf("p3 address [%p] value is %s\n", p3, p3);  /* Fixed format specifiers */
   return 0;
}

样例输出


ch : Hello
p1 address [0x7fff58e45666] value is Hello
p2 address [0x7fff58e45666] value is Hello
p3 address [0x7fff58e45666] value is Hello

2
从重复的副本中进行逐字复制粘贴的目的是什么? - Oliver Charlesworth
2
@OliCharlesworth OP注意到他/她已经浏览了现有的答案,因此我选择了一个特别好的答案,并用略微离题的回答加以阐述。 还引用了一些来源。 - Cloud
1
@Dogbert我试着做了一些测试,写了一个测试程序,但它崩溃了,你能告诉我原因吗?我已经编辑了我的原始帖子。 - AALC
@AALC 我已经发布了对你的编辑的详细回复。它应该能够澄清并解释为什么你的程序失败了,并提供了解决方案。 - Cloud
1
@Dogbert 很棒的解释,对我帮助很大,谢谢 :) - AALC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接