为什么 char 类型指针数组 wsklan[0] 和 wsklan[0][0] 中的地址不同?
Why do addresses in array of char type pointers wsklan[0] and wsklan[0][0] differ?
对你来说这可能是一个愚蠢的问题,我找不到一个好的问题,但问题是 - 我不明白,我要求你向我解释这个概念,这样我就可以明白了,我将不胜感激。
所以,问题是 - 首先,我想知道为什么那行代码:
printf("address of wsklan[0] %p\n", &wsklan[0])
打印的地址不同于:
printf("address of wsklan[0][0] %p\n", &wsklan[0][0]);
我猜这是因为在第一种情况下,这是一个指针的地址,而在第二种情况下,这是一个 char 变量的地址。但为什么地址不一样呢?我以为wsklan[0]的地址是第一个char的地址。
字符串在内存中是如何存储的?字符串在内存中是一个接一个吗?所以如果我输入 'onetwo' 和第二个字符串 'threefour',它会是一个接一个吗?
第二个问题 - 为什么我不能像这样使用 puts 函数?:
puts(wsklan+1)
但我可以这样使用它吗?
puts(wsklan[1])
完整代码片段:
#include <stdio.h>
#include <string.h>
char *read(char *z, int amount);
int main(void){
char data[20][300];
char * wsklan[20];
read(data[0], 300);
read(data[1], 300);
wsklan[0] = data[0];
wsklan[1] = data[1];
printf("addres wsklan[0][0] %p\n", &wsklan[0][0]);
printf("addres wsklan[1][0] %p\n", &wsklan[1][0]);
puts(wsklan[0]);
puts(wsklan[1]);
putchar(*wsklan[1]);
return 0;
}
char *read(char *z, int amount){
char * res;
int i = 0;
res = fgets(z, amount, stdin);
if(res){
while(z[i] != '\n' && z[i] != '[=14=]')
i++;
if(z[i] != '\n')
z[i] = '[=14=]';
else
while(getchar() != '\n')
continue;
}
return res;
}
感谢您的理解并帮助我从总体上理解这个概念。该代码片段来自 Stephen Prata 的 C 书,我对其进行了一些修改。
假设声明是char * wsklan[20];
.
在表达式&wsklan[0]
中,[]
优先于&
,所以我们得到指针编号0。然后&
给出该指针的地址。由于它是数组中的第一项,您可以假设它与通过 &wsklan
.
获得的地址相同
在表达式 &wsklan[0][0]
中我们也得到指针编号 0,然后 []
再次优先于 &
所以我们在数组中得到字符编号 0
该指针0号点在。然后 &
给出该单个字符的地址。那是什么地址取决于您将指针设置为指向的位置。它指向与指针本身存储位置不同的地址,这是完全有道理的。 (因为指向它自己地址的指针将毫无用处。)
第二个问题:wsklan[1]
100% 等同于 *(wsklan + 1)
。所以它与 wsklan + 1
具有不同的含义。由于该变量属于“字符指针数组”类型,因此在表达式中使用时它会“衰减”为指向第一项的指针。那将是一个指向字符指针的指针,char**
。这不是 printf 所期望的 - 您必须首先将其取消引用为普通 char*
。
为了论证方便,让我们假设如下:
sizeof(char)
是 1(根据定义)
sizeof(char *)
是 4(例如在具有 32 位指针的系统上)
char data[20][300]
存储在地址10000(任意)
char *wsklan[20]
存储在地址20000(任意)
然后:
&wsklan[0]
转换为 (char **)20000
&wsklan[1]
转换为 (char **)20004
&wsklan[2]
转换为 (char **)20008
Note: Unary &
has lower precedence than [
]
, so &wsklan[0]
means &(wsklan[0])
.
和:
data[0]
和 &data[0][0]
转换为 (char *)10000
data[1]
和 &data[1][0]
转换为 (char *)10300
data[2]
和 &data[2][0]
转换为 (char *)10600
Note: &data[0][0]
means &((data[0])[0])
.
之后:
wsklan[0] = data[0];
wsklan[1] = data[1];
然后:
wsklan[0]
和&wsklan[0][0]
转换为(char *)10000
(与data[0]
和&data[0][0]
相同)
wsklan[1]
和&wsklan[1][0]
转换为(char *)10300
(与data[1]
和&data[1][0]
相同)
从上面比较&wsklan[0]
和&wsklan[0][0]
总结一下:
&wsklan[0]
转换为 (char **)20000
&wsklan[0][0]
转换为(char *)10000
(等同于&data[0][0]
)
对你来说这可能是一个愚蠢的问题,我找不到一个好的问题,但问题是 - 我不明白,我要求你向我解释这个概念,这样我就可以明白了,我将不胜感激。
所以,问题是 - 首先,我想知道为什么那行代码:
printf("address of wsklan[0] %p\n", &wsklan[0])
打印的地址不同于:
printf("address of wsklan[0][0] %p\n", &wsklan[0][0]);
我猜这是因为在第一种情况下,这是一个指针的地址,而在第二种情况下,这是一个 char 变量的地址。但为什么地址不一样呢?我以为wsklan[0]的地址是第一个char的地址。
字符串在内存中是如何存储的?字符串在内存中是一个接一个吗?所以如果我输入 'onetwo' 和第二个字符串 'threefour',它会是一个接一个吗?
第二个问题 - 为什么我不能像这样使用 puts 函数?:
puts(wsklan+1)
但我可以这样使用它吗?
puts(wsklan[1])
完整代码片段:
#include <stdio.h>
#include <string.h>
char *read(char *z, int amount);
int main(void){
char data[20][300];
char * wsklan[20];
read(data[0], 300);
read(data[1], 300);
wsklan[0] = data[0];
wsklan[1] = data[1];
printf("addres wsklan[0][0] %p\n", &wsklan[0][0]);
printf("addres wsklan[1][0] %p\n", &wsklan[1][0]);
puts(wsklan[0]);
puts(wsklan[1]);
putchar(*wsklan[1]);
return 0;
}
char *read(char *z, int amount){
char * res;
int i = 0;
res = fgets(z, amount, stdin);
if(res){
while(z[i] != '\n' && z[i] != '[=14=]')
i++;
if(z[i] != '\n')
z[i] = '[=14=]';
else
while(getchar() != '\n')
continue;
}
return res;
}
感谢您的理解并帮助我从总体上理解这个概念。该代码片段来自 Stephen Prata 的 C 书,我对其进行了一些修改。
假设声明是char * wsklan[20];
.
在表达式&wsklan[0]
中,[]
优先于&
,所以我们得到指针编号0。然后&
给出该指针的地址。由于它是数组中的第一项,您可以假设它与通过 &wsklan
.
在表达式 &wsklan[0][0]
中我们也得到指针编号 0,然后 []
再次优先于 &
所以我们在数组中得到字符编号 0
该指针0号点在。然后 &
给出该单个字符的地址。那是什么地址取决于您将指针设置为指向的位置。它指向与指针本身存储位置不同的地址,这是完全有道理的。 (因为指向它自己地址的指针将毫无用处。)
第二个问题:wsklan[1]
100% 等同于 *(wsklan + 1)
。所以它与 wsklan + 1
具有不同的含义。由于该变量属于“字符指针数组”类型,因此在表达式中使用时它会“衰减”为指向第一项的指针。那将是一个指向字符指针的指针,char**
。这不是 printf 所期望的 - 您必须首先将其取消引用为普通 char*
。
为了论证方便,让我们假设如下:
sizeof(char)
是 1(根据定义)sizeof(char *)
是 4(例如在具有 32 位指针的系统上)char data[20][300]
存储在地址10000(任意)char *wsklan[20]
存储在地址20000(任意)
然后:
&wsklan[0]
转换为(char **)20000
&wsklan[1]
转换为(char **)20004
&wsklan[2]
转换为(char **)20008
Note: Unary
&
has lower precedence than[
]
, so&wsklan[0]
means&(wsklan[0])
.
和:
data[0]
和&data[0][0]
转换为(char *)10000
data[1]
和&data[1][0]
转换为(char *)10300
data[2]
和&data[2][0]
转换为(char *)10600
Note:
&data[0][0]
means&((data[0])[0])
.
之后:
wsklan[0] = data[0];
wsklan[1] = data[1];
然后:
wsklan[0]
和&wsklan[0][0]
转换为(char *)10000
(与data[0]
和&data[0][0]
相同)wsklan[1]
和&wsklan[1][0]
转换为(char *)10300
(与data[1]
和&data[1][0]
相同)
从上面比较&wsklan[0]
和&wsklan[0][0]
总结一下:
&wsklan[0]
转换为(char **)20000
&wsklan[0][0]
转换为(char *)10000
(等同于&data[0][0]
)