1

pC99 では、変数を配列型の引数を持つ関数にパラメーターとして渡す前に、配列へのポインターとして変数を宣言する必要があるのはなぜですか。変数pを void ポインターとして宣言してから、配列へのポインターにキャストする配列へのポインタとして同じ関数に渡されますか?

#include <stdio.h>

int arreglo(int locArr[])
{
    locArr[0]=1;
    printf("el arreglo es : %i\n",locArr[0]);
    return 0;
}

int main()
{
    /* Declare a pointer p to array */
    int (*p)[];

    int manArr[10];

    p=&manArr;   /* assign the adress of manArr as case below */

    /* Here passing pointer p is not allowed as expected,
       since our function has int* as argument */         

    /* so I need to do a casting */
    arreglo((int*)p);   
}

/* **But in this other main function**: */

int main()
{
    /* Declare a void pointer  */
    void *p=NULL;

    /* Do a casting from p to void to p to array */
    p=(int (*)[])p;

    int manArr[10];

    p=&manArr;  /* assing the adress of the array manArr as in above case */

    /* Now given the pointer to array as parameter to function WORKS¡¡,
       why?. As before the function expects int* as argument not
       a pointer to an array */  

    arreglo(p);

}
4

3 に答える 3

3

array-of-int と pointer-to-int は同等ですが、pointer-to-array(-of-int) は余分なレベルの間接性です。

以下は、いくつかのコメントと修正を加えたプログラムです。

#include<stdio.h>

int arreglo(int locArr[])
{
    locArr[0]=1;
    printf("el arreglo es : %i\n",locArr[0]);
    return 0;
}

int main()
{
    /* Declare a pointer p to array */
    //int (*p)[]; //NO!
    /* Declare a pointer p to int */
    int *p;

    int manArr[10];


    //p=&manArr;   /* assign the adress of manArr as case below */  //NO!
    p=manArr;

    /* Here passing pointer p is not allowed as expected,
       since our function has int* as argument */ // Because `int*` and `int (*)[]` are different

    /* so I need to do a casting */ //NO! 
    //arreglo((int*)p);   
    arreglo(p);
}

/* **But in this other main function**: */

int main()

{
    /* Declare a void pointer  */
    void *p=NULL;

    /* Do a casting from p to void to p to array */
    //p=(int (*)[])p;  //NO! This does absolutely nothing at all.

    int manArr[10];

    //p=&manArr;  /* passing the adress of the array manArr as in above case */
    p=manArr;

    /* Now given the pointer to array as parameter to function WORKS¡¡,
       why?. As before the function expects int* as argument not
       a pointer to an array */  
    // A void* bypasses all type-checking, since it can be implicitly converted to any type

    arreglo(p); //This would still compile if p="potato", because a void* converts to any type.

}

それでは、最初からやり直しましょう。

int i = 0;              // a simple int variable
int a[3] = { 1, 2, 3 }; // an array of ints
int *p = a;             // a pointer to int can be used the same as an array of int
p[0] = 4;               // so now a[0] = 4, too

int i   int a[3]
|----|  |----|----|----|
|  0 |  |  4 |  2 |  3 |
|----|  |----|----|----|
           ^
int *p     |
|----|     |
|  --|-----
|----|

配列へのポインターは、配列の一部である場合とそうでない場合がある単一の int だけでなく、配列全体を指すため、まったく異なります。

 int b[3] = { 5, 6, 7 };
 int (*bp)[3] = &b;   // bp points to the whole array b

     -------------
     V            |
 int b[3]         |  int (*bp)[3]
 |----|----|----| |  |----|
 |  5 |  6 |  7 |  --|--  |
 |----|----|----|    |----|

 bp[0][0] = 8;  // it now takes 2 dereferences to get to the int

     -------------
     V            |
 int b[3]         |  int (*bp)[3]
 |----|----|----| |  |----|
 |  8 |  6 |  7 |  --|--  |
 |----|----|----|    |----|
于 2013-07-03T02:41:36.010 に答える
1

これは、長い間考えた後、質問に答えようとする試みです..:) 間違っている場合は修正してください。

次の行p=(int (*)[])p;は の型には影響しませんppはまだタイプでありvoid *(したがって、キャストは冗長です)、void *任意のデータポインタータイプと互換性があるため、関数呼び出しは問題ありません。

最初のmain()関数については、あなたが書いていると考えています。

こちらをご覧ください(混乱を避けるためによくお読みください)。

編集:

つまり、 of 式のタイプを変更しようとしていlhsます。これは型キャストの目的ではありません。

詳細に:

特定の型の式を別の型に変換することを と呼びtype-castingます。

それでは、次の行を分析してみましょう: 式の をp=(int (*)[])p; 考えます。です(さすが)。しかし、それを( )に割り当てたいとします。任意の型のポインターを許可するため、コンパイラーは文句を言いません。これも(暗黙的に)に型キャストされます。rhs(int (*)[])ppointer to arrays of integer pointersvoid *operator =void *pointer to arrays of integer pointersvoid *

試してください: p=(*whatever type you like*)p; コンパイラは文句を言いません.(実行されるとは思わないでください..:))

于 2013-07-03T01:49:41.113 に答える
0

main()以下は、変数pとを使用して の 2 つのバリアントを 1 つに結合する、コードの単純な適応ですq

#include <stdio.h>

static int counter = 0;
static int arreglo(int locArr[])
{
    locArr[0] = ++counter;
    printf("el arreglo es: %i\n", locArr[0]);
    return 0;
}

int main(void)
{
    int manArr[10];
    int (*p)[] = &manArr;

    /* Here passing pointer p is not allowed as expected, since
    ** the function has int* as argument so I need to cast it...
    */
    arreglo((int*)p);
    printf("manArr[0] = %d\n", manArr[0]);

    /* Or, since p is a pointer to an array, *p is the array,
    ** which can be passed directly without a cast.
    */
    arreglo(*p);
    printf("manArr[0] = %d\n", manArr[0]);

    void *q = NULL;

    /* This is a no-op */
    q = (int (*)[])q;   /* Cast from q to void to q to array */

    q = &manArr;  /* assign the address of the array manArr as above */

    /* Now given the pointer to array as parameter to function WORKS¡¡
    ** Why?. As before the function expects int* as argument not
    ** a pointer to an array
    */
    arreglo(q);
    printf("manArr[0] = %d\n", manArr[0]);

    /* Convert the void * back to a pointer to array, then dereference it */
    arreglo(*(int (*)[])q);
    printf("manArr[0] = %d\n", manArr[0]);

    return 0;
}

キャストなしで に渡すことができなかった理由は、型 'pointer to array of p'が'pointer to ' と同じではなく、関数へのパラメーターが 'pointer to ' と同等であるためです。あなたのキャストはコンパイラをあなたに同意させました. の型が間違っていても、その値 (バイトアドレス) は関数が期待する配列の開始要素のアドレスと同じであるため、あなたはそれを回避します. コメントに記載されているように、配列へのポインターがあり、関数は配列を想定しているため、キャストを必要とせずに渡すことができます。arreglo()intintintp*p

void *バージョン (ab) は、C でキャストせずに a をオブジェクト型への他のポインターに変換できるという事実を使用しますvoid *(C++ ではキャストが必要です)。を使用しているため、コンパイラは警告できませんvoid *。繰り返しますが、タイプは異なりますが、&manArrのバイト アドレスは のバイト アドレスと同じであるため、問題はありません。&manArr[0]明示的なキャスト (配列へのポインターに戻る) と逆参照が機能することに注意してください。

注意してくださいvoid *; 型情報が失われます。それは恩恵になる可能性があります。また、重大な問題を隠すこともできます。

通常、配列へのポインターはまったく使用しません。それらは、型の C パンテオンの 'esoterica' セクションに存在します。通常、次のようなコードを記述します。

#include <stdio.h>

static int counter = 0;

static int arreglo(int locArr[])
{
    locArr[0] = ++counter;
    printf("el arreglo es: %i\n", locArr[0]);
    return 0;
}

int main(void)
{
    int manArr[10];
    int *p = manArr;

    arreglo(p);
    printf("manArr[0] = %d\n", manArr[0]);
    return 0;
}

これは、理解するのがはるかに簡単です。

于 2013-07-04T00:33:59.337 に答える