指向数组困境的指针

时间:2012-09-06 18:14:01

标签: c++ c pointer-arithmetic

关于数组和指向数组的指针,我有一个相当简单的问题。 考虑这段代码..

int (*ptr)[3];               //A pointer to an array of 3 ints
int arr1[3] = {2,4,6,};      
ptr = &arr1;                //ptr now points to arr1

//3 different ways to express  the same address
cout << &arr1 << "\t" << arr1 << "\t" << &arr1[0] << endl;

现在如果:

&arr1 == arr1 == &arr1[0]..

为什么这段代码不正确:

ptr = arr1;

ptr = &arr1[0];

这让我发疯了...所以请任何解释都会受到赞赏。另外请不要这不是一个家庭作业问题,只是我想要抓住的东西。

4 个答案:

答案 0 :(得分:5)

ptr = arr1;

arr1转换为int*,因此您尝试从不兼容的指针类型进行分配。 &arr1[0]直接是int*,没有转换,因此再次不兼容。

&arr1 == arr1 == &arr1[0]

是错误的,因为实体有不同的类型。它们只指向相同的地址,因此在打印时,它们会给出相同的结果。

答案 1 :(得分:3)

在大多数情况下,具有数组类型的表达式被隐式转换为指向此类数组的第一个元素的指针,如6.3.2.1p3所述:

  

除非它是sizeof运算符,_Alignof运算符或者&运算符的操作数。   一元ptr = arr1; 运算符,或者是用于初始化数组的字符串文字,一个包含的表达式   type 类型的数组将转换为类型指向类型的指针的表达式   到数组对象的初始元素,而不是左值。

因此,作业的右侧

int*

隐式转换为不兼容的指针类型(int (*)[3]&),并且在没有强制转换的情况下无法存储到指针变量中。

这对任何规则都不是一个例外,因为你需要将一元T val, *ptr; ptr = &val; 运算符与其他类型一起使用:

{{1}}

答案 2 :(得分:1)

  

以下程序将帮助您更好地了解它们之间的区别       pointer_to_first_member_of_array,pointer_to_1D_array,pointer_to_2D_array。       请仔细查看程序,执行它并查看输出。

/****************************************************/
/************* datetime Example Client **************/
/****************************************************/

#include "datetime.h"

int main( int argc , char * * argv )
{
    int sockfd , n ;
    char recvline[ MAXLINE + 1];
    struct sockaddr_in servaddr;

    if( argc != 2 )  {
        printf( "usage : a.out <IP address>\n" );
        exit( 1 );
    }

    if( ( sockfd = socket( AF_INET , SOCK_STREAM , 0 ) ) < 0 ) {
        printf( "socket error\n" );
        exit( 1 );
    }

    memset( &servaddr , 0 , sizeof( servaddr ) );
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons( 13 );

    if( inet_pton( AF_INET , argv[ 1 ] , &servaddr.sin_addr ) <= 0 )  {
        printf( "inet_pton error for %s\n" , argv[ 1 ] );
        exit( 1 ); 
    }

    if( connect( sockfd , (struct sockaddr *)&servaddr , sizeof( servaddr ) ) < 0 )  {
        printf( "connect error\n" );
        exit( 1 );
    }

    while( ( n = read( sockfd , recvline , MAXLINE ) ) > 0 )  {
        recvline[ n ] = 0;
        if( fputs( recvline , stdout ) == EOF ) {
            printf( "fputs error\n" );
            exit( 1 );
        }
    }

    if( n < 0 )  {
        printf( "read error\n" );
        exit( 1 );
    }
    exit( 0 );  
}

答案 3 :(得分:0)

当您打印各种表达时,它会向您显示其是相同的。但是,它们没有相同的类型

C和C ++包含类型功能,可以减少人为错误并使编写复杂代码变得更容易。假设你在某个指针p中有一个地址,C / C ++允许你这样做:

float *f = p;

或:

int *i = p;

这将是一个错误,因为通常,p中的内存中的任何位都不代表有用的int和有用的float。通过强制执行有关类型的规则,该语言可以防止程序员在这里犯错;指针p只能分配给兼容类型的另一个指针,除非程序员使用强制转换显式覆盖规则。

同样,您的ptr是指向三个int数组的指针。首先,您的arr1似乎也是一个包含三个int的数组,因此您应该能够分配ptr = arr1;。这是错误的,因为ptr只是一个指针,但arr1是一个完整的数组对象。你不能把整个数组放到指针中;你需要将一个指向数组的指针放入指针中。要获取指向数组的指针,请使用&运算符:ptr = &arr1;

另一件令人困惑的事情是C / C ++包含一个自动快捷方式:它将数组转换为指向数组第一个元素的指针。在大多数情况下arr1出现时,它会自动更改为&arr1[0]。这没有一个巨大的哲学原因;它只是方便我们经常使用数组的方式。因此ptr = arr1;等同于ptr = &arr1[0];,这也是不允许的。在这种形式中,您可以看到arr1已成为指向int的指针,因此您无法将其指定给指向int数组的指针。即使指针具有您想要的,也是错误的类型

当数组显示为&sizeof_Alignof的操作数时,不会发生此自动转换。所以&arr1会产生数组的地址。

char a[] = "abc";这样的初始化中使用的字符串文字是专门处理的,不会如上所述自动转换。