2009-06-29 11 views
4

弊社次のコードを持っている:printf引数に関する質問。 C/C++

char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'}; 
printf("%s\n", tab); 

そして、我々は printfへの呼び出しでエラー/警告を取得しない理由を私は理解していません。 私は警告を受け取りますが、エラーは発生せず、プログラムはうまく動作します。 '12'と印刷されます。
printfは、タイプchar *の引数、つまりcharへのポインタを想定しています。だから私がchar arr[3]と宣言した場合、arrcharを含むメモリユニットのアドレスなので、printfを呼び出すと、へのポインタへのポインタ、つまりchar *になります。
同様に、tab 3チャーの順番にあるの種類アレイを含むメモリユニットのアドレスであり、メモリユニットのアドレスがcharが含まれ、これtabchar **に減衰し、それが問題であるべきで、以来printfchar *と予想しています。

誰かがこの問題について説明できますか?

補遺:

私が手に警告がある:
a.c:6: warning: char format, different type arg (arg 2)

+0

以下、あなたはそれがうまくいっていると言いますが、ここではあなたは「エラー/警告」を得ると述べています。何を正確に得ますか?このエラーが発生しやすいコードで警告が表示されるのは論理的ですが、エラーが発生しますか? –

+0

私は追加され、修正されました。 –

答えて

6

例ソース

#include <stdio.h> 

int main(void) { 
    char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'}; 
    printf("%s\n", tab); 

    return 0; 
} 

コンパイル

 
$ gcc test.c 
test.c: In function ‘main’: 
test.c:5: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[3]’

ポインタがprintfから%s引数は、それの機能を示しポインタ

ある警告(文字列への)ポインタを受け取ります。文字列は、Cでは、単にASCII-Zで終わる一連のバイトです。 tab[2][3]変数はポインタです。一部のコンパイラは、ポインタの不一致に関する警告を発行します。しかし、printfのコードは、ゼロバイトが見つかるまで与えられたポインタ(開始時に文字を表示する)からメモリを横断するので、コードはまだ12を出力するはずです。 1,2および\ 0は、tab変数で表されるアドレスから開始して、メモリ内で連続して設定されます。

実験

実験として次のコードをコンパイルして実行すると、何が起こる:

#include <stdio.h> 

int main(void) { 
    char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'}; 
    printf("%s\n", tab[1]); 

    return 0; 
} 

は、実験を恐れてはいけません。あなたが今知っていることに基づいて答えを考え出すことができるかどうかを見てください。現在、tabを参照して(実験に照らして)、警告を取り除き、まだ12と表示していますか?

+0

これは簡単です。 printfを呼び出すのは正しい方法です。 tab [1]はchar []型で、printfをchar *で呼び出すのと同じです。だからすべてが最適です。 –

+0

正確に。したがって、 "12"を表示するには、tab [0]を使用します。 –

1

あなたはそれを自分で説明しているように見える、私が言って残っているものは表示されません。

tabは、2つのchar *の配列です。 tabの各要素は、printfが受け入れることができる文字列ですが、tab自体は受け入れられません。これは、charへのポインタへのポインタであるためです。

+0

しかし、それは動作します! '12 'を表示します。 –

+1

タブとタブ[0]は同じ位置( "12"文字列)を指しているため、不一致にもかかわらず両方が機能します。 –

+0

あなたの問題は、コンパイラがコードを受け入れているようです。これがなぜそうであるかのNeil Butterworthの答えを見てください。率直に言って、私はコンパイラがprintf()のセマンティクスを認識していて、その引数についてどんな種類の型チェックを行っているのに驚いています。 – Ari

4

tabパラメータは、printf()呼び出しのelipsisと一致します。 CおよびC++コンパイラは、このようなパラメータをチェックする義務を負いません。 tabchar **に減衰すること

3

あなたの仮定が間違っている:tabは、それがchar (*) [3]に減衰する。すなわち、char [2][3]を入力しています。配列とポインタはしばしば同じように振る舞いますが、同じことではないことを理解することが重要です。 printf()char *を想定しているため、char (*) [3]のビットを取り、それに従って解釈します。あなたのプラットフォームでは動作しますが、Cの標準ではこれは保証されていません。両方のポインタが同じメモリ位置を参照しますが、その表現は同一である必要はありません。

詳細については、my answer~this related questionを参照してください。

+0

+1、私はそれがすでにどこかで答えられていたことを知っていましたが、私はその質問を見つけませんでした。私が見つけたのはこれだけです:http://stackoverflow.com/questions/232303/so-you-think-you-know-pointers – quinmars