0

首先,我读到:

  • array
  • &array
  • &array[0]

只要“array”真的是一个数组,它们都是一样的。所以我尝试了:

int main(){ 
     char ar[]={'a','b','c','\0'};
     printf("argument: &ar     %s\n",&ar);
     printf("argument: &ar[1]    %s\n",&ar[1]);
}

输出:

argument:&ar   abc  
argument:&ar[1]  bc

似乎它&ar被视为指向第一个元素的指针,而不是指向“ar”的指针,如果我没记错的话,它本身就是指向第一个元素的指针。

因为这不应该是 &(pointer to a char) 的处理方式,我试过:

char a='s';
char *pa=&a;
printf("argument: &pa   %c\n",&pa);

的输出%c甚至不是一个字符。也不应该是如何处理指向数组第一个元素的指针。我试过:

char *pa=&ar[0];
char **ppa= &pa;
printf("argument: &pa   %s\n", ppa);

%s毫不奇怪,输出是胡说八道;但为什么没有&ar胡说八道?因为如果ar是一个指针,不应该&ar是指向指针的指针ppa吗?

我的问题:

  1. 将“&”放在数组名称之前是否会被忽略?数组名称是否只是特殊的?
  2. 如果是这样,编译器如何验证“&”后面的标识符是对数组的引用?它实际上是否在声明的数组列表中搜索它?
4

3 回答 3

2

似乎这&ar被视为指向第一个元素的指针而不是指向“ar”的指针,如果我没记错的话,它本身就是指向第一个元素的指针的指针。

你错了 &ar是指向数组的指针ar,但数组ar不是任何类型的指针(它是数组),因此&ar也不是指向指针的指针。

数组是一个连续的对象序列 - 在 的情况下ar,它是一个连续的 4 chars 集合。 &ar是指向这组 4 个字符的指针,这必然意味着它与 指向同一位置&ar[0],指向char该集中第一个字符的指针。但是,它具有不同的类型:&arhas typechar (*)[4]表示“指向 4 个字符的数组的指针”,并&ar[0]has typechar *表示“指向 char 的指针”。

之所以会产生混淆,是因为在几乎所有表达式中,都会ar计算出指向数组第一个元素的指针(例外情况是它是一元运算&符或运算符的操作数sizeof)。这并不意味着它ar 一个指针——它不是——只是在大多数情况下它计算为一个指针值。

于 2012-07-19T02:35:11.157 回答
1

printf 格式 %s 的意思是“对应的参数是一个指向 char 的指针。在那个位置打印字符串。” 为此,字符串是以空字符结尾的字符序列。

当您传递&ar给 printf 时,您传递了“a”的地址(尽管类型错误;printf 需要一个指向字符的指针,而您传递了一个指向字符数组的指针,但它们具有相同的地址),并且 printf 看到了字符串 'a'、'b'、'c'、'\0',所以它打印了“abc”。ar如果您通过或&ar[0];也会发生同样的情况 那些评估到相同的地址。

当你传递&ar[1]给 printf 时,你传递了一个指向 'b' 所在位置的指针,并且 printf 看到了字符串 'b'、'c'、'\0',所以它打印了“bc”。

如果您只想在某个位置传递单个字符,请使用 %c 格式并传递一个字符(而不是指向字符的指针)。例如,如果您使用 %c 格式*ar,将打印 'a',如果您使用 %c 和*&ar[1],将打印 'b'。

似乎 &ar 被视为指向第一个元素的指针,而不是指向“ar”的指针,如果我没记错的话,它本身就是指向第一个元素的指针。

在表达式中使用时,ar充当指向数组第一个元素的指针,与&ar[0]. &ar并且ar是相同的地址(数组中的第一个字符与数组的开头位于相同的地址),尽管它们具有不同的类型(指向 char 数组的指针和指向 char 的指针)。

%c 的输出甚至不是字符

它是一个字符,只是不是您所期望的,可能不是普通字符或可打印字符。%c 期望传递一个字符参数,但您传递了一个地址参数。

如果是这样,编译器如何验证“&”后面的标识符是否引用了数组,它实际上是否在声明的数组列表中搜索它?

解析比这更复杂(本质上,标识符在考虑 & 之前被识别为已知数组,然后计算 & 和标识符的组合表达式)。但是,效果是&ar计算到与第一个元素相同的地址。

于 2012-07-19T02:38:09.813 回答
1

如果您的代码在没有警告的情况下编译,则说明您没有充分利用您的编译器。如果您要求它这样做,它将对您有所帮助。了解如何让它在编译时出现警告,并了解如何修复它诊断出的问题。我使用以下命令中的一个或另一个编译了以下代码:

gcc -O3 -g -std=c99 -Wall -Wextra -m64 array-stuff.c -o array-stuff
gcc -O3 -g -std=c99 -Wall -Wextra -m32 array-stuff.c -o array-stuff

这是使用 GCC 编写干净代码的一个很好的起点。确实,-Wall没有-Wextra也很好。

这是您的代码的改编版(在文件中array-stuff.c)-尽管其中大部分都不同:

#include <stdio.h>
#include <inttypes.h>

int main(void)
{ 
    // DC4M = Doesn't compile for me, because I compile with stringent warnings
    char ar[16] = { 'a', 'b', 'c', '\0' };  // Note explicit size
    printf("%-18s  %s\n", "Code:", "char ar[16] = { 'a', 'b', 'c', '\0' };");
    //printf("argument: &ar     %s\n", &ar);    // DC4M
    printf("argument: &ar[1]  %s\n", &ar[1]);

    printf("%-18s  0x%" PRIXPTR "\n", "ar:",       (uintptr_t)ar);
    printf("%-18s  0x%" PRIXPTR "\n", "&ar:",      (uintptr_t)&ar);
    printf("%-18s  0x%" PRIXPTR "\n", "(ar+1):",   (uintptr_t)(ar+1));
    printf("%-18s  0x%" PRIXPTR "\n", "(&ar+1):",  (uintptr_t)(&ar+1));
    printf("%-18s  0x%" PRIXPTR "\n", "&ar[1]:",   (uintptr_t)(&ar[1]));
    printf("%-18s  0x%" PRIXPTR "\n", "&(ar[1]):", (uintptr_t)(&(ar[1])));
    printf("%-18s  0x%" PRIXPTR "\n", "(&ar)[1]:", (uintptr_t)((&ar)[1]));

    printf("%-18s  %zu\n", "sizeof(ar):",       sizeof(ar));
    printf("%-18s  %zu\n", "sizeof(&ar):",      sizeof(&ar));
    printf("%-18s  %zu\n", "sizeof(void*):",    sizeof(void*));
    printf("%-18s  %zu\n", "sizeof(ar[1]):",    sizeof(ar[1]));
    printf("%-18s  %zu\n", "sizeof(&ar[1]):",   sizeof(&ar[1]));
    printf("%-18s  %zu\n", "sizeof(&(ar[1])):", sizeof(&(ar[1])));
    printf("%-18s  %zu\n", "sizeof((&ar)[1]):", sizeof((&ar)[1]));

    {
    char  a = 's';
    char *pa = &a;
    printf("%-18s  %s\n", "Code:", "char  a = 's';");
    printf("%-18s  %s\n", "Code:", "char *pa = &a;");
    //printf("argument: &pa   %c\n", &pa);    // DC4M
    printf("%-18s  0x%" PRIXPTR "\n", "&pa:",  (uintptr_t)&pa);
    printf("%-18s  0x%" PRIXPTR "\n", "&a:",   (uintptr_t)&a);
    printf("%-18s  0x%" PRIXPTR "\n", "pa:",   (uintptr_t)pa);
    }

    {
    char  *pa = &ar[0];
    char **ppa = &pa;
    //printf("argument: &pa   %s\n", ppa);  // DC4M
    printf("%-18s  %s\n", "Code:", "char  *pa = &ar[0];");
    printf("%-18s  %s\n", "Code:", "char **ppa = &pa;");

    printf("%-18s  0x%" PRIXPTR "\n", "&pa:",  (uintptr_t)&pa);
    printf("%-18s  0x%" PRIXPTR "\n", "ppa:",  (uintptr_t)ppa);
    printf("%-18s  0x%" PRIXPTR "\n", "*ppa:", (uintptr_t)*ppa);
    printf("%-18s  0x%" PRIXPTR "\n", "&ppa:", (uintptr_t)&ppa);
    }

}

这是具有 64 位编译的 Mac OS X 10.7.4 机器的输出:

Code:               char ar[16] = { 'a', 'b', 'c', '
argument: &ar[1]  bc
ar:                 0x7FFF6C9DE570
&ar:                0x7FFF6C9DE570
(ar+1):             0x7FFF6C9DE571
(&ar+1):            0x7FFF6C9DE580
&ar[1]:             0x7FFF6C9DE571
&(ar[1]):           0x7FFF6C9DE571
(&ar)[1]:           0x7FFF6C9DE580
sizeof(ar):         16
sizeof(&ar):        8
sizeof(void*):      8
sizeof(ar[1]):      1
sizeof(&ar[1]):     8
sizeof(&(ar[1])):   8
sizeof((&ar)[1]):   16
Code:               char  a = 's';
Code:               char *pa = &a;
&pa:                0x7FFF6C9DE560
&a:                 0x7FFF6C9DE56F
pa:                 0x7FFF6C9DE56F
Code:               char  *pa = &ar[0];
Code:               char **ppa = &pa;
&pa:                0x7FFF6C9DE558
ppa:                0x7FFF6C9DE558
*ppa:               0x7FFF6C9DE570
&ppa:               0x7FFF6C9DE550

这是 32 位编译的输出:

Code:               char ar[16] = { 'a', 'b', 'c', '
argument: &ar[1]  bc
ar:                 0xC008A670
&ar:                0xC008A670
(ar+1):             0xC008A671
(&ar+1):            0xC008A680
&ar[1]:             0xC008A671
&(ar[1]):           0xC008A671
(&ar)[1]:           0xC008A680
sizeof(ar):         16
sizeof(&ar):        4
sizeof(void*):      4
sizeof(ar[1]):      1
sizeof(&ar[1]):     4
sizeof(&(ar[1])):   4
sizeof((&ar)[1]):   16
Code:               char  a = 's';
Code:               char *pa = &a;
&pa:                0xC008A668
&a:                 0xC008A66F
pa:                 0xC008A66F
Code:               char  *pa = &ar[0];
Code:               char **ppa = &pa;
&pa:                0xC008A664
ppa:                0xC008A664
*ppa:               0xC008A670
&ppa:               0xC008A660

当您了解各种数字是如何得出的时,您就会很好地理解事物。

注意&array[1]被解释为&(array[1]); 它与(&array)[1]类型和大小不同。数组下标等后缀运算符比地址 ( &) 和间接 ( *) 运算符等一元运算符绑定得更紧密。

于 2012-07-19T03:38:15.080 回答