🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

3回答

515閲覧

文字列とポインタの配列の違いが分からない

takilice

総合スコア4

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2021/03/06 14:48

前提

最近、ポインタを勉強し始めたばかりなので、そもそも理解しきれていない可能性があります。
ご教授いただければ幸いです。

問題

以下のプログラムでは、格配列の文字列の個数3が定数としてプログラム中(for文の制御式)に埋め込まれている。計算によって求めるように書き換えたプログラムを作成せよ。

c

1#include <stdio.h> 2 3int main (void) 4{ 5 int i; 6 char a[][5] = {"LISP", "C", "Ada"}; 7 char *p[] = {"PAUL", "X", "MAC"}; 8 9 for(i = 0; i < 3; i++) 10 printf("a[%d] = \"%s\"\n", i, a[i]); 11 for(i = 0; i < 3; i++) 12 printf("p[%d] = \"%s\"\n", i, p[i]); 13 14 return 0; 15}

該当のソースコード

c

1#include <stdio.h> 2 3int main(void) 4{ 5 int i, n = 0; 6 char a[][5] = {"LISP", "C", "Ada"}; 7 char *p[] = {"PAUL", "X", "MAC"}; 8 9 for (i = 0; a[i][0] != '\0'; i++) { 10 n++; 11 } 12 13 for (i = 0; i < n; i++) { 14 printf("a[%d] = \"%s\"\n", i, a[i]); 15 } 16 17 for (i = 0; i < n; i++) { 18 printf("p[%d] = \"%s\"\n", i, p[i]); 19 } 20 21 return 0; 22}

実行した結果

c

1a[0] = "LISP" 2a[1] = "C" 3a[2] = "Ada" 4a[3] = "" 5a[4] = "??6" 6a[5] = "???" 7p[0] = "PAUL" 8p[1] = "X" 9p[2] = "MAC"

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2021/03/06 16:22

a は文字の 2 次元配列で、p はポインタの配列、という違いはお分かりでしょうか?
takilice

2021/03/07 01:38

ありがとうございます。 先ほど、他の方からの解説で理解しました。
guest

回答3

0

ベストアンサー

otnさんの回答のとおり、取り組まれている問題の回答としては
a[i][0] != '\0'でサイズを確認してしまっていることがNGになります。

運が良ければ、メモリ上にあるゴミを触るだけで動いてしまいますが、二次元配列aもポインタ配列pも4番目以降は、自分のしらないメモリ領域なので、本来安易にアクセスしてはいけないのです。
そのため、この問題のように、事前にさわってもよい領域のサイズを事前に計算させてその部分にだけアクセスします。
別なやり方として、最初にメモリ確保して、全部'\0'で初期化しておいたものを用意するか、かならず最後の要素は'\0'にすることを保証するなら、たしかにtakiliceさんのようなやり方でもよいです。
実際には、メモリ確保すると、それを開放するまで面倒をみる必要がありますし、ポインタの最後の要素にかならず'\0'が入っているという決まりが保証されていない場合も多いので、簡単な操作がしたいときはotnさんのようなやり方でサイズをチェックするやり方が常套手段なように思います。

二次元配列aとポインタ配列pの動きの違いは、コンパイラやOSの動作や、メモリになんのゴミが入っているかに依存していると思います。
私のほうでやってみたら、Mac環境では、takiliceさんとおなじような動きになりましたが、ポインタ配列pは、「Segmentation fault: 11」がでました。
Linux環境では、どちらも最後の要素を'\0'にしてくれるようで、動いてしまいました。あくまで私の環境でやった結果です。

投稿2021/03/06 23:46

NGW

総合スコア48

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takilice

2021/03/07 01:36

回答ありがとうございます。 違いをわかりやすく教えて頂き、すごく助かりました。
guest

0

char a[][5] = {"LISP", "C", "Ada"}; は、次の実行結果と同じ。

C

1 char a[3][5]; 2 a[0][0] = 'L', a[0][1] = 'I', a[0][2] = 'S', a[0][3] = 'P', a[0][4] = 0; 3 a[1][0] = 'C', a[1][1] = 0, a[1][2] = 0, a[1][3] = 0, a[1][4] = 0; 4 a[2][0] = 'A', a[2][1] = 'd', a[2][2] = 'a', a[2][3] = 0, a[2][4] = 0;

char *p[] = {"PAUL", "X", "MAC"}; は、次の実行結果と同じ。

C

1 char *p[3]; 2 static char a[5] = { 'P', 'A', 'U', 'L', 0 }; 3 static char b[2] = { 'X', 0 }; 4 static char c[4] = { 'M', 'A', 'C', 0 }; 5 p[0] = &a[0]; // p[0] = a; でも同じ 6 p[1] = &b[0]; // p[1] = b; でも同じ 7 p[2] = &c[0]; // p[2] = c; でも同じ

配列の要素数を定数で書かない書き方。

C

1 char a[][5] = {"LISP", "C", "Ada"}; 2 char *p[] = {"PAUL", "X", "MAC"}; 3 4 for(i = 0; i < sizeof a / sizeof a[0]; i++) 5 printf("a[%d] = \"%s\"\n", i, a[i]); 6 for(i = 0; i < sizeof p / sizeof p[0]; i++) 7 printf("p[%d] = \"%s\"\n", i, p[i]);

sizeof a[0] は 5。sizeof a は 15。
sizeof a / sizeof a[0] はコンパイル時に 3 になります。
実行時に割り算を実行するわけではありません。

sizeof p[0] はポインタだから 8 または 4。sizeof p は 24 または 12。
sizeof p / sizeof p[0] はコンパイル時に 3 になります。
実行時に割り算を実行するわけではありません。

投稿2021/03/06 23:35

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takilice

2021/03/07 01:34

回答ありがとうございます。 実際のコードの書き方も書いてくださり、すごくわかりやすかったです。
guest

0

どちらも配列なので、配列の要素数は、「配列のサイズ / 配列要素のサイズ」で求まります。

C

1size = sizeof 配列名 / sizeof 配列名[0];

投稿2021/03/06 15:24

otn

総合スコア85886

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takilice

2021/03/07 01:33

回答ありがとうございます。 解決しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問