字符串文本和数组的地址

Address of a string literal and array

提问人:Sanjay Verma 提问时间:4/13/2020 最后编辑:RobertS supports Monica CellioSanjay Verma 更新时间:11/17/2023 访问量:1251

问:

    int main(){
        char *str1="Hi", *str2 = "Bye";
        printf("%u,%u\n",&str1,str1);
        int arr[5]={1,2,3,4,5};
        printf("%u,%u",arr,&arr);
    }

这是怎么回事? 并给出不同的地址和相同的地址。str&strarr&arr

我的理解是,它指向第一个元素的地址,即,并且还会给出相同的地址,但它是整体的地址。如果我们增加 1,那么它将指向 arr[4] 的下一个元素。但问题是,为什么这个过程在字符串的情况下是不同的。请帮我在这里想象这个概念。arr&arr[0]&arrarr[5]&arr

c 数组 字符串 指针 string-literals

评论

2赞 znatno 4/13/2020
这回答了你的问题吗?理解指针的障碍是什么,可以做些什么来克服它们?

答:

1赞 RobertS supports Monica Cellio 4/13/2020 #1

1.

char *str1="Hi";
printf("%u,%u\n",&str1,str1);

首先,对 和 使用了错误的转换说明符,这将调用未定义的行为。因为它将是,因为它将是:%ustr1&str1str1%s&str1%p

char *str1="Hi";
printf("%p,%s\n",(void*) &str1, str1);

解释:

str1是指向字符串文本的第一个元素的地址的指针。 是指针本身的地址。这就是与下面数组的版本的区别。"Hi"&str1str1


2.

int arr[5]={1,2,3,4,5};
printf("%u,%u",arr,&arr);

同样,此处的转换说明符错误。它应该是 或者,如果你想打印 as 的第一个元素,或者如果你想打印第一个元素的地址:%d%iarrarrintunsigned int%p

int arr[5]={1,2,3,4,5};
printf("%p,%p",(void*) arr, (void*) &arr);

解释:

arr(在数组到指针衰减规则之后)衰减到指向第一个元素的指针,而实际上是指向第一个元素的指针。他们实际上评估相同。arr&arrarr


请注意,强制转换为是使代码 C 符合标准所必需的。void*

7赞 Some programmer dude 4/13/2020 #2

在 C 语言中,所有字符串文字实际上都存储为(只读)字符数组,包括一个 null 终止符。与任何其他数组一样,它们衰减为指向其第一个元素的指针。

因为在您的代码中,编译器生成了一些类似于以下内容的代码:str1

// Compiler-generated array for the string
char global_array_for_Hi[] = { 'H', 'i', '\0' };

int main(void)
{
    char *str1 = global_array_for_Hi;
    ...
}

指针变量指向此数组的第一个元素 (the )。当您打印时,该值就是您获得的值。str1'H'str1

当你打印 的值时,你会得到变量本身的位置,你会得到一个指向 类型的指针。&str1str1str1char **

从图形上看,它可以看作是

+-------+     +------+     +-----+-----+------+
| &str1 | --> | str1 | --> | 'H' | 'i' | '\0' |
+-------+     +------+     +-----+-----+------+

因为你有一个数组,它会衰减为指向其第一个元素的指针。当你使用时,它与 相同(它来自完全等于 的事实)。(和)的类型是 。arrarr&arr[0]arr[i]*(arr + i)arr&arr[0]int *

当你使用时,你会得到一个指向整个数组的指针,它的类型是 。&arrint (*)[5]

和 的位置相同,但它们的类型却大不相同。&arr[0]&arr


与此相关的是,printf 格式说明符用于打印 类型的值。要打印指针(更具体地说是 type 的值),必须使用 format 说明符 。格式说明符和参数类型不匹配会导致未定义的行为%uunsigned intvoid *%p

评论

0赞 Sanjay Verma 4/13/2020
如果我定义 str1[]=“Hi”,那么它的行为会像我提到的数组一样吗?
0赞 Michael Schäfer 4/13/2020
我是 C 语言的新手。为什么你/编译器声明 char 数组是全局的?
0赞 Some programmer dude 4/13/2020
@MichaelSchäfer 所有文字字符串都是“全局”的,并且具有完整程序的生命周期。有关详细信息,请参阅此字符串文本引用
0赞 Michael Schäfer 4/13/2020
@Someprogrammerdude 从您的链接中,字符串文字是不可修改的。字符串文字 like 是不可修改的。在您的示例中,str1 是可修改的。在声明数组时是否忘记了常量,或者编译器是否以不同的方式处理它?char *str1="Hi"
1赞 Some programmer dude 4/13/2020
@MichaelSchäfer 问题是编译器创建的字符串数组不是 .尝试修改一个将导致未定义的行为,因此它们实际上是只读的(正如我提到的),但它们不是。在标准 C 中,除了 之外,没有办法将数组标记为“不可修改”,但由于它们不是,所以我省略了这一点。constconstconstconst
1赞 0___________ 4/13/2020 #3

array不是指针。它是连续的内存块。这就是为什么&&具有相同地址的原因。array&array

pointer是一个变量,用于保存对另一个变量的引用。因此,为您提供指针所持有的引用/地址,并为您提供对本身的引用/地址。由于指针是一个单独的“对象”,因此您有不同的地址。pointer&pointerpointer

1赞 Vlad from Moscow 4/13/2020 #4

在本声明中

char *str1="Hi", *str2 = "Bye";

声明了两个局部变量,并具有自动存储持续时间。str1str2

它们由具有静态存储持续时间的字符串文本的第一个字符的地址初始化。

所以 的值是字符串文字的第一个字符的地址。表达式的值是局部变量本身的地址。str1"Hi"&str1str1

你可以这样想象

&str1 ---> str1 ---> "Hi"

数组是连续的内存范围。因此,数组本身的地址和它的第一个元素的地址是相同的。它是数组占用的内存范围的地址。

你可以这样想象

        | 1 | 2 | 3 | 4 | 5 |
        ^
        |        
&arr----
        ^
        |
arr-----

请注意,表达式中使用的数组指示符(极少数例外)将转换为指向其 firs 元素的指针。所以使用 din 调用 printf 的表达式等价于 .arr&arr[0]

关于您的评论

弗拉德 我对字符串常量有疑问,为什么我们不能修改这个 char *s=“HI”,但我们可以修改这个 char *s[]=“HI” 我知道第二个 如果它是简单的数组,但你能清楚为什么我不能修改吗 字符串常量

然后根据 C 标准(6.4.5 字符串文字)

7 没有具体说明这些数组是否不同,前提是它们的 元素具有适当的值。如果程序尝试 修改这样的数组,行为是未定义的。

请注意此声明

char *s[]="HI";

无效。声明了一个指针数组。所以要初始化它,你必须写

char * s[] = { "HI" };

您可以通过为数组元素分配其他字符串文字来更改数组的元素。也就是说,您可以更改指针本身,而不是指针指向的字符串文字。

评论

0赞 Sanjay Verma 4/13/2020
弗拉德我对字符串常量有疑问,为什么我们不能修改这个字符 *s=“HI”,但我们可以修改这个字符 *s[]=“HI” 我知道第二种情况它是简单的数组,但你能清楚为什么我不能修改字符串常量。
0赞 Vlad from Moscow 4/13/2020
@SanjayVerma 请参阅我附加的答案。
1赞 ravivasani75 4/13/2020 #5

在 C 语言中,像“Hi, Guys”这样的常量字符串存储在共享内存中。 请看以下示例:

str = "Hi, there";

上述代码中的字符串是连续存储的。变量指向 字符串的第一个字符,所以这里的字符“H”。 因此,给出存储在内存中某个位置的第一个字符的地址。 给出变量本身的地址。strstr&strstr

数组中的大小写与上面不同。 数组是变量(当然,const 变量),包含数组的第一个元素(即 &arr[0])的地址。当你这样做时,它将与 .&arr 实际上是整个数组的地址,与数组第一个元素的地址相同。&arr&arr[0]

注意:打印和,你可能会得到一些光线。&arr + 5&arr[0] +5

评论

0赞 Sanjay Verma 4/13/2020
是的,ravi 我知道数组它们的行为方式,但我对 str[] 和 *str 感到困惑,我认为它们的工作方式相同,但它们是不同的。顺便说一句,感谢您的回答。