提问人:Sanjay Verma 提问时间:4/13/2020 最后编辑:RobertS supports Monica CellioSanjay Verma 更新时间:11/17/2023 访问量:1251
字符串文本和数组的地址
Address of a string literal and array
问:
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
&str
arr
&arr
我的理解是,它指向第一个元素的地址,即,并且还会给出相同的地址,但它是整体的地址。如果我们增加 1,那么它将指向 arr[4] 的下一个元素。但问题是,为什么这个过程在字符串的情况下是不同的。请帮我在这里想象这个概念。arr
&arr[0]
&arr
arr[5]
&arr
答:
1.
char *str1="Hi";
printf("%u,%u\n",&str1,str1);
首先,对 和 使用了错误的转换说明符,这将调用未定义的行为。因为它将是,因为它将是:%u
str1
&str1
str1
%s
&str1
%p
char *str1="Hi";
printf("%p,%s\n",(void*) &str1, str1);
解释:
str1
是指向字符串文本的第一个元素的地址的指针。 是指针本身的地址。这就是与下面数组的版本的区别。"Hi"
&str1
str1
2.
int arr[5]={1,2,3,4,5};
printf("%u,%u",arr,&arr);
同样,此处的转换说明符错误。它应该是 或者,如果你想打印 as 的第一个元素,或者如果你想打印第一个元素的地址:%d
%i
arr
arr
int
unsigned int
%p
int arr[5]={1,2,3,4,5};
printf("%p,%p",(void*) arr, (void*) &arr);
解释:
arr
(在数组到指针衰减规则之后)衰减到指向第一个元素的指针,而实际上是指向第一个元素的指针。他们实际上评估相同。arr
&arr
arr
请注意,强制转换为是使代码 C 符合标准所必需的。void*
在 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
当你打印 的值时,你会得到变量本身的位置,你会得到一个指向 类型的指针。&str1
str1
str1
char **
从图形上看,它可以看作是
+-------+ +------+ +-----+-----+------+ | &str1 | --> | str1 | --> | 'H' | 'i' | '\0' | +-------+ +------+ +-----+-----+------+
因为你有一个数组,它会衰减为指向其第一个元素的指针。当你使用时,它与 相同(它来自完全等于 的事实)。(和)的类型是 。arr
arr
&arr[0]
arr[i]
*(arr + i)
arr
&arr[0]
int *
当你使用时,你会得到一个指向整个数组的指针,它的类型是 。&arr
int (*)[5]
和 的位置相同,但它们的类型却大不相同。&arr[0]
&arr
与此相关的是,printf
格式说明符用于打印 类型的值。要打印指针(更具体地说是 type 的值),必须使用 format 说明符 。格式说明符和参数类型不匹配会导致未定义的行为。%u
unsigned int
void *
%p
评论
char *str1="Hi"
const
const
const
const
array
不是指针。它是连续的内存块。这就是为什么&&具有相同地址的原因。array
&array
pointer
是一个变量,用于保存对另一个变量的引用。因此,为您提供指针所持有的引用/地址,并为您提供对本身的引用/地址。由于指针是一个单独的“对象”,因此您有不同的地址。pointer
&pointer
pointer
在本声明中
char *str1="Hi", *str2 = "Bye";
声明了两个局部变量,并具有自动存储持续时间。str1
str2
它们由具有静态存储持续时间的字符串文本的第一个字符的地址初始化。
所以 的值是字符串文字的第一个字符的地址。表达式的值是局部变量本身的地址。str1
"Hi"
&str1
str1
你可以这样想象
&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" };
您可以通过为数组元素分配其他字符串文字来更改数组的元素。也就是说,您可以更改指针本身,而不是指针指向的字符串文字。
评论
在 C 语言中,像“Hi, Guys”这样的常量字符串存储在共享内存中。 请看以下示例:
str = "Hi, there";
上述代码中的字符串是连续存储的。变量指向
字符串的第一个字符,所以这里的字符“H”。
因此,给出存储在内存中某个位置的第一个字符的地址。 给出变量本身的地址。str
str
&str
str
数组中的大小写与上面不同。
数组是变量(当然,const 变量),包含数组的第一个元素(即 &arr[0])的地址。当你这样做时,它将与 .&arr 实际上是整个数组的地址,与数组第一个元素的地址相同。&arr
&arr[0]
注意:打印和,你可能会得到一些光线。&arr + 5
&arr[0] +5
评论