指针还是地址?
Pointer or address?
// Capitalizes a copy of a string while checking for errors
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// Get a string
char *s = get_string("s: "); //this is in the cs50.h
char *t = malloc((strlen(s) + 1) * sizeof(char));
// Copy string into memory
for (int i = 0, n = strlen(s); i <= n; i++)
t[i] = s[i];
return 0;
}
以上代码来自cs50 2018第3讲。 t[i] = s[i]
部分让我感到困惑。据我所知,当我们说 char *t
时, t
将存储分配的内存第一部分的地址。那么 t[i]
不是给我们 t[i]
位置的内存地址吗?如果是这样,我们是不是应该写
*t[i] = s[i]
更改 t[i]
的值 ?
不,[]
数组索引运算符 取消引用 指针并求值为值本身,而不是其地址。表达式 s[i]
等同于表达式 *(s + i)
。如果您想要索引 i
处的元素的地址,则需要使用 &
运算符,如 &s[i]
(相当于 s + i
)。
int array[] = { 10, 20, 30, 40 }; // create an array for illustration
int *ptr = array; // array type decays to a pointer
// these print the same thing: the address of the array element at index 2
printf("%p\n", ptr + 2); // pointer arithmetic
printf("%p\n", &ptr[2]); // array index operator followed by address-of operator
// these print the same thing: the element at index 2 (= 30)
printf("%d\n", *(ptr + 2)); // pointer arithmetic followed by dereference operator
printf("%d\n", ptr[2]); // array index operator
t[i]
实际上给你数组的第 i
个元素。它的工作原理与 s[i]
相同,后者具有相同的类型。
语法 t[i]
与 *(t + i)
完全相同。换句话说,执行指针运算以获得指向所需元素的指针,然后解引用结果以获取实际元素。
char *s = ...;
char *t = ...;
...
t[i] = s[i];
t[i]
是一个 左值 ,一个引用对象的表达式。过于简单化一点 [*],如果它出现在赋值的左侧(就像它在这里所做的那样),它指的是一个特定的 char
对象,并且赋值会更新该对象的值。 s[i]
类似,但它出现在赋值的右侧,因此它产生对象的 value。
本质上是一样的:
int x;
int y;
y = x;
x
和 y
都是对象的名称,它们都是左值。左侧的 y
指的是对象。右侧的 x
产生存储在对象中的值。
[*] 过于简单化的是,除了赋值的左侧之外,还有其他上下文,其中左值引用对象而不是产生其值。
[]
运算符的定义方式(见 comp.lang.c FAQ)第 6 节数组和指针之间的关系),但在这种情况下,你真正需要知道的是 s[i]
和 t[i]
是对象的名称。
C 标准 N1570 draft 的第 6.3.2.1 节
中有血淋淋的细节
// Capitalizes a copy of a string while checking for errors
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
// Get a string
char *s = get_string("s: "); //this is in the cs50.h
char *t = malloc((strlen(s) + 1) * sizeof(char));
// Copy string into memory
for (int i = 0, n = strlen(s); i <= n; i++)
t[i] = s[i];
return 0;
}
以上代码来自cs50 2018第3讲。 t[i] = s[i]
部分让我感到困惑。据我所知,当我们说 char *t
时, t
将存储分配的内存第一部分的地址。那么 t[i]
不是给我们 t[i]
位置的内存地址吗?如果是这样,我们是不是应该写
*t[i] = s[i]
更改 t[i]
的值 ?
不,[]
数组索引运算符 取消引用 指针并求值为值本身,而不是其地址。表达式 s[i]
等同于表达式 *(s + i)
。如果您想要索引 i
处的元素的地址,则需要使用 &
运算符,如 &s[i]
(相当于 s + i
)。
int array[] = { 10, 20, 30, 40 }; // create an array for illustration
int *ptr = array; // array type decays to a pointer
// these print the same thing: the address of the array element at index 2
printf("%p\n", ptr + 2); // pointer arithmetic
printf("%p\n", &ptr[2]); // array index operator followed by address-of operator
// these print the same thing: the element at index 2 (= 30)
printf("%d\n", *(ptr + 2)); // pointer arithmetic followed by dereference operator
printf("%d\n", ptr[2]); // array index operator
t[i]
实际上给你数组的第 i
个元素。它的工作原理与 s[i]
相同,后者具有相同的类型。
语法 t[i]
与 *(t + i)
完全相同。换句话说,执行指针运算以获得指向所需元素的指针,然后解引用结果以获取实际元素。
char *s = ...;
char *t = ...;
...
t[i] = s[i];
t[i]
是一个 左值 ,一个引用对象的表达式。过于简单化一点 [*],如果它出现在赋值的左侧(就像它在这里所做的那样),它指的是一个特定的 char
对象,并且赋值会更新该对象的值。 s[i]
类似,但它出现在赋值的右侧,因此它产生对象的 value。
本质上是一样的:
int x;
int y;
y = x;
x
和 y
都是对象的名称,它们都是左值。左侧的 y
指的是对象。右侧的 x
产生存储在对象中的值。
[*] 过于简单化的是,除了赋值的左侧之外,还有其他上下文,其中左值引用对象而不是产生其值。
[]
运算符的定义方式(见 comp.lang.c FAQ)第 6 节数组和指针之间的关系),但在这种情况下,你真正需要知道的是 s[i]
和 t[i]
是对象的名称。
C 标准 N1570 draft 的第 6.3.2.1 节
中有血淋淋的细节