为什么不能将指针用于索引数组?

时间:2019-05-09 20:19:28

标签: c arrays pointers

我正在尝试使用指针更改字符数组组件的值。但是我不能这样做。使用两种不同的方法char A[]char *A声明数组之间有根本的区别吗?

我尝试使用A[0]访问数组,并且可以正常工作。但是我无法更改数组组件的值。

{
    char *A = "ab";
    printf("%c\n", A[0]); //Works. I am able to access A[0]
    A[0] = 'c'; //Segmentation fault. I am not able to edit A[0]
    printf("%c\n", A[0]);
}

预期输出:

a
c

实际输出:

a
Segmentation fault

4 个答案:

答案 0 :(得分:3)

区别在于char A[]定义了一个数组,而char *没有定义一个数组。

要记住的最重要的事情是数组不是指针

在此声明中:

char *A = "ab";

字符串文字"ab"创建一个类型为char[3]的匿名数组对象(终结点'\0'用2加1)。该声明创建了一个名为A的指针,并将其初始化为指向该数组的初始字符。

由字符串文字创建的数组对象具有静态存储持续时间(这意味着它在程序的整个执行过程中都存在),并且不允许您对其进行修改。 (严格来说,尝试对其进行修改具有未定义的行为。)它实际上应该是const char[3]而不是char[3],但是由于历史原因,它没有被定义为const。您应该使用指向const的指针来引用它:

const char *A = "ab";

,以便编译器将捕获任何修改数组的尝试。

在此声明中:

char A[] = "ab";

字符串文字具有相同的作用,但是数组对象A用该数组内容的副本初始化。数组A是可修改的,因为您没有使用const定义它-并且因为它是您创建的数组对象,而不是由字符串文字隐式创建的,所以您可以对其进行修改。

A[0]这样的数组索引表达式实际上需要一个指针作为其操作数(另一个为整数)。通常,该指针是数组表达式“衰减”到指针的结果,但也可以只是一个指针-只要该指针指向数组对象的元素即可。

C中的数组和指针之间的关系很复杂,并且那里存在许多错误信息。我建议阅读comp.lang.c FAQ的第6节。

可以使用数组名称或指针来引用数组对象的元素。您遇到了只读数组对象的问题。例如:

#include <stdio.h>
int main(void) {
    char array_object[] = "ab"; /* array_object is writable */
    char *ptr = array_object;   /* or &array_object[0] */
    printf("array_object[0] = '%c'\n", array_object[0]);
    printf("ptr[0] = '%c'\n", ptr[0]);
}

输出:

array_object[0] = 'a'
ptr[0] = 'a'

答案 1 :(得分:2)

字符串文字不打算被覆盖,请将其视为只读。覆盖字符串是未定义的行为,因此您的计算机选择了使程序崩溃。您可以使用数组来修改字符串。

char A[3] = "ab";
A[0] = 'c';

答案 2 :(得分:2)

"ab"这样的字符串文字被假定为是不可变的,就像其他任何文字一样(您不能更改1或{{1 }}, 例如)。但是,与数字文字不同,字符串文字 require 需要某种形式的存储。有些实现(例如您正在使用的实现)显然将字符串文字存储在只读存储器中,因此尝试更改文字的内容将导致段错误。

语言定义使行为未定义-可能按预期运行,可能会完全崩溃,或者可能会执行其他操作。

答案 3 :(得分:1)

  

使用两种不同的方法char A[]char *A声明数组之间有根本区别吗?

是的,因为第二个不是数组而是指针。

"ab"的类型为char /*readonly*/ [3]。它是具有不变内容的数组。因此,当您想要指向该字符串文字的指针时,应使用指向char const的指针:

char const *foo = "ab";

这可以防止您意外更改文字。但是,如果您想使用字符串文字来初始化数组:

char foo[] = "ab";  // the size of the array is determined by the initializer
                   //  here: 3 - the characters 'a', 'b' and '\0'

然后可以修改该数组的元素。

数组索引btw只是语法糖:

foo[bar];  /* is the same as */  *(foo + bar);

这就是为什么人们可以做一些有趣的事情

"Hello!"[2];  /* 'l'   but also */  2["Hello!"];  // 'l'