使用字符指针和字符数组的区别

21

基础问题。

char new_str[]="";

char * newstr;
如果我需要将一些数据连接在一起或使用字符串函数(如strcat/substr/strcpy),这两种方法之间有什么区别?
我知道我需要为char *方法分配内存(第2行)。但我不确定该怎么做。
const char *和字符串字面量是相同的吗?
我需要更多信息。有人可以指向一些详尽的内容/材料吗?

1
看看这个惊人的教程:http://pw2.netcom.com/~tjensen/ptr/cpoint.htm - jyz
9个回答

11
解决混淆的最佳来源是Peter Van der Linden的Expert C Programming, Deep C secrets - 数组和指针不同的地方在于它们在内存中的寻址方式。对于一个数组,例如
char new_str[];
,编译器在编译和运行时都知道new_str的内存地址,例如0x1234,因此可以简单地使用[]进行索引。例如,new_str[4] 在运行时,代码会选择new_str所在的地址,例如0x1234(即物理内存中的地址),通过加上索引说明符[4], 0x1234 + 0x4,就可以检索到该值。
而对于指针,编译器为符号
char *newstr
分配一个地址,例如0x9876,但在运行时,该地址是一种间接寻址方案。假设newstr被malloc'd
newstr = malloc(10);
,每次在代码中使用newstr进行引用时,由于编译器知道newstr的地址即0x9876,但newstr指向的却是一个可变变量。在运行时,代码从物理内存0x9876(即newstr)中获取数据,但在该地址处是另一个内存地址(因为我们使用了malloc),例如0x8765,在这里,代码从malloc分配给newstr的内存地址0x8765中获取数据。char new_str[]char *newstr是可以互换使用的,因为数组的零元素索引会转化为指针,这解释了为什么你可以使用newstr [5]或者*(newstr+5)。注意,即使我们声明了char *newstr,指针表达式也被使用,因此
*(new_str+1)=*newstr;
或者
*(new_str+1)=newstr[1];

总之,两者之间的实际区别在于它们在内存中的访问方式。

购买这本书,阅读它,体验它,并且深入理解它。这是一本绝妙的书! :)


3
附带说明:C语言的表达式具有可交换性,例如4 + 3与3 + 4相同。指针也是如此, (new_str + 1)与(1 + new_str)相同,巧合的是它等同于1[new_str],这是一个笑话,并被引用到了网络上的其他地方,可能是为了迷惑某些人。它很少在生产中使用,我还没有看到过其在任何地方的应用! - t0mm13b

9
请阅读以下文章:这篇文章
对于字符数组,例如 char new_str[],则 new_str 将始终指向数组的基地址。指针本身无法递增。是的,您可以使用下标来访问数组中的下一个字符,例如: new_str[3]
但是对于指向字符的指针,则可以通过递增指针 new_str++ 来获取数组中的下一个字符。
此外,我建议您阅读这篇文章以获得更清晰的解释。

3
两个链接现在都已失效 :( - matt b

6

这是一个字符数组:

char  buf [1000];

例如,这句话没有意义:

buf = &some_other_buf;

这是因为buf虽然具有指针类型的特征,但它已经指向了唯一有意义的位置。
char *ptr;

另一方面,ptr 只是一个指针,可能指向任何地方。通常情况下,它可能是这样的:

ptr = buf;              // #1:  point to the beginning of buf, same as &buf[0]

也许是这个:
ptr = malloc (1000);    // #2:  allocate heap and point to it

或者:

ptr = "abcdefghijklmn"; // #3:  string constant

对于所有这些情况,*ptr 可以被写入 - 除了第三种情况,在某些编译环境中定义字符串常量为不可写。

*ptr++ = 'h';          // writes into #1: buf[0], #2: first byte of heap, or
                       //             #3 overwrites "a"
strcpy (ptr, "ello");  // finishes writing hello and adds a NUL

2

它们的区别在于一个是指针,另一个是数组。例如,您可以使用sizeof()来获取数组的大小。您可能会对查看此处感兴趣。


1

第一个的类型是char [1],第二个是char *。类型不同。

在C中使用malloc或在C++中使用new为后者分配内存。

char foo[] = "Bar";  // Allocates 4 bytes and fills them with
                     // 'B', 'a', 'r', '\0'.

这里的大小是从初始化字符串中推断而来的。

foo 的内容是可变的。例如,您可以更改 foo[i],其中 i = 0..3。

另一方面,如果您这样做:

char *foo = "Bar";

编译器现在将一个静态字符串“Bar”分配到只读内存中,无法修改。
foo[i] = 'X';  // is now undefined.

嗯,不行。foo是不可变的。你不能改变foo本身。你可以改变foo的元素,但如果bar也是一个字符数组,你不能将foo更改为bar。 - Johann Gerell

1
如果您正在使用C++,那么您应该使用C++字符串,而不是C语言的char数组。
string类型使得操作字符串变得更加容易。
如果由于某种原因您必须使用char数组,请注意以下代码行:
char new_str[] = "";

分配了1个字节的空间并将一个空终止符字符放入其中。它与以下内容略有不同:

char *new_str = "";

因为那可能会给您一个非可写内存的参考。该语句:

char *new_str;

单独使用它会给你一个指针,但不会指向任何东西。如果它是函数的局部变量,它也可能具有随机值。

人们倾向于在C中执行以下操作(而不是C++):

char *new_str = malloc (100); // (remember that this has to be freed) or
char new_str[100];

获取足够的空间。

如果你使用 str... 函数,你基本上需要确保在 char 数组中有足够的空间,否则你会得到各种奇怪和精彩的调试代码实践。如果你使用真正的 C++ 字符串,很多重活都为你完成了。


0
为了在内存分配方面区分它们:
// With char array, "hello" is allocated on stack
char s[] = "hello";

// With char pointer, "hello" is stored in the read-only data segment in C++'s memory layout.
char *s = "hello";

// To allocate a string on heap, malloc 6 bytes, due to a NUL byte in the end
char *s = malloc(6);
s = "hello";

0
char new_str[]="abcd";  

这指定了一个大小为5个字节的字符数组(字符串)(每个字符一个字节加上一个空终止符)。因此,它将字符串“abcd”存储在内存中,我们可以使用变量new_str访问该字符串。

char *new_str="abcd";  

这指定了一个字符串 'abcd' 存储在内存中的某个位置,而指针 new_str 指向该字符串的第一个字符。


-2
如果你在使用C++,为什么不使用std::string来满足你所有的字符串需求呢?特别是任何涉及到字符串连接的操作。这将避免许多问题的出现。

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