はじめまして、工学系の大学生です。C言語について質問です。
文字単体をデータとして配列を作るなら、例えば
char [100];
で構わないと思うのですが、文字列を1つのデータとして配列を作る場合はどうしたらいいのでしょうか?僕が思いついたのは2次元配列を用いて1つの次元をデータ数、もう1つの次元を各データの最大文字数として例えば
char name[100][20];
のように定義して、
name[0][]=David;
name[1][]=Mathew;
などととすれば、printf関数でname[0]を出力したらDavidが出てくれるかと思ったのですが、エラーがたくさん出てきてしまいました。
もしよろしければどなたか教えていただけないでしょうか?どうぞよろしくおねがいしますm(_ _)m
No.5ベストアンサー
- 回答日時:
引き続き回答します。
なるほど、ちょっと配列の根本を見直してみましょう。
if(name[i][10]==comp[5])
は何をしようとしているかはわかります。
きっと文字列比較をしたいのでしょう。
しかし、実際希望の処理は行われていません。では何が行われているか考えてみてください。
char name[5][10]={"David","Mathew","Linda","Pole","Thomas"};
char comp[5]="Pole";
とすると何が格納されるのでしょうか。
DavidとPoleについて考えます。
name[0][0]には D
name[0][1]には a
name[0][2]には v
name[0][3]には i
name[0][4]には d
name[0][5]には \0
それ以降には何も入っていません。
つまり(null)です。
そして
comp[0]には P
comp[1]には o
comp[2]には l
comp[3]には e
comp[4]には \0
それ以降は何も無し。
つまり(null)です。
上記の通り
name[0][10]には何も入っていません。(null)です。
comp[5]にも何も入っていません。(null)です。
つまり
if(name[i][10]==comp[5])
は何も入っていない配列要素の1つと
何も入っていない配列要素の1つを比較しているのです。
なのでPoleが一致したからif文内のprint文が実行されたわけではありません。
比べたものはnullとnull。つまり何もないものと何もないものを比較して何もないという意味では一緒だと
処理されたのでしょう。
つまりその考え方なら、毎回一致するはずですが、なぜfor文の最後だけ一致したのかはわかりません。
後で、何故なったのか実行しながら考えて見ます。
ところで、配列について見直します。
配列は要素数を示さず書くと何を示しているか知っていますか?
その配列が始まる先頭アドレスです。
アドレスとかポインタとか言うと入門者さんは頭を抱えてしまうと思いますが、
難しく考えないで下さい。
全てのデータはデータのアドレスで管理されています。
22234番地にこのデータ、45342番地にこのデータと言う具合です。
配列によって今10要素を宣言すると連続した番地にデータが用意されます。
つまり
231~241番地に用意されるといった具合です。
今
name[0][0]と指定すると格納した値"D"が示されますが
name[0]と指定すると、その配列が始まる先頭のアドレス、つまりこの場合231番地が示されるわけです。
文字列比較をする場合はこの番地(ポインタといいます)で比較しなければなりません。
(そうではなくて文字列の2番目の要素と文字列の3番目の要素を比較すると言った具合に特定の文字を比較するのでしたら要素数を指定する必要があります。)
if(name[0] == "David")
とすると希望の比較が出来ると思うでしょう。
前述どおりname[0]は文字列の先頭アドレスを示してますよね。
ここのアドレスのデータからデータの値がDavidですと。
一方、比較の右辺この場合の"David"は見た目わかりませんが、この""の部分も自然とポインタの比較をしていることになります。
文字列の中身を比較してくれるわけではありません。
つまり文字列の中身を比較する関数を利用して比較する必要があります。
strcmpという関数があります。
strcmp(name[0], "David");
この返り値が0なら文字列は同じ、
0以外なら文字列は違います。
つまり文字列を比較したい時は
if(strcmp(name[0], "David") == 0)
printf("2つの文字列は同じ\n");
こんな感じになります。
つまりcompと比較したいのならばcomp
if(strcmp(name[0], comp) == 0)
printf("2つの文字列は同じ\n");
こうなりますね。
では希望通りの処理が出来るようにプログラムを書いてみます。
#include <stdio.h>
#include <string.h>
int main(void)
{
int i;
char name[5][10]={"David","Mathew","Linda","Pole","Thomas"};
char comp[5]="Pole";
for(i=0;i<=4;i++){
if(strcmp(name[i],comp)==0){
printf("Poleは配列 name の中にあります。\n");
printf("そのデータナンバーは %d です。\n",i);
printf("name[%d]=%s と comp=%s を比較した時に確認しました。\n",i,name[i],comp);
}
}
return 0;
}
難しい事は何も書いてありませんからゆっくり見てください。
また、何か分からない事があったら何でも聞いてください。
おっしゃる通りポインタやらアドレスやらで頭痛を起こす人間です(笑)
でもdra2jpさんの解説はとてもわかりやすいので質問した部分に関してはおおかた理解できました☆そして配列の考え方のみならずアドレスの基本まで教えていただけるとは…多謝多謝ですm(__)m
No.7
- 回答日時:
#2>for文を使って反復命令として実行できないかということです。
C言語では動的に変数名を合成・作成して変数にアクセスするというようなことができないので、配列などに格納してfor で回すようにします。
変数名を別につける理由がないなら、for で配列で使うような用途であれば、最初から配列にします。
また、C言語では、変数名に「-」は、使えなかったと思います。(演算子に解釈されるため、例えばname-a[n] は、name - a[n]と解釈されます。)
----------------------------------------------------------------
#include <stdio.h>
#include <string.h>
int main(void){
char name_a[]="David";
char name_b[]="Mathew";
char name_c[]="Smith";
char name_x[]="Smith";
char *name[3];
int i;
name[0]=name_a;
name[1]=name_b;
name[2]=name_c;
for(i=0;i<=2;i++){
if(strcmp(name[i], name_x)==0){
printf("This list has same data to name-x.");
break;
}
}
return 0;
}
なるほど、変数名に数値を勝手に入れて動かしたりはできないのですね。イメージ的に動きそうだったのですが…プログラムで文法を気にせず自分のイメージなどに従うなど言語道断ですね(汗)なんだか主題以外に色々な知識を頂戴できました。ありがとうございます☆
No.6
- 回答日時:
この回答は下を読んだ後、補足として
お読みください。
ちょっと気になりましたが、配列について色々誤解されていらっしゃる部分が多いようですので、
この回答を見た後で、配列について参考書やウェブなどでおさらいして置いてください。
printf("name[0][10] = %s.\n",name[0]);
の部分で気になりました。
name[0][10]の部分には文字1文字しかはいりません。
配列要素の1つにすぎません。
name[0]にはそこから始まる文字列の先頭アドレスが示されています。
つまり
char name[1][11] ="01234567890";
と宣言した時には
name[0][10]には0が入っています。
printf("name[0][10] = %c.\n",name[0][10]);
の表示は
0
です。
printf("name[0][10] = %s.\n",name[0]);
と書いていらっしゃるので、一応文字列はname[0]で示す事をしっていらっしゃるとは思いますが・・。
char name[8]="David";
と宣言した時、文字列Davidを示したい時は[]無しで
name
とだけで示しますよね?
この配列の中身(配列要素)はなんでしょうか。
name[0]には D
name[1]には a
name[2]には v
name[3]には i
name[4]には d
name[5]には \0
name[6]には null(何も無し)
name[7]には null(何も無し)
そして
name には 文字列の先頭アドレス(私のパソコンの場合1245060)が格納されています。
前にも書いた通り、配列要素のアドレスは連続しています。
このことを確認するために次のようなプログラムを実行して確認してください。
#include <stdio.h>
int main(void)
{
int i;
char name[8]="David";
printf(" name[0]=%c\n name[1]=%c\n name[2]=%c\n name[3]=%c\n name[4]=%c\n name[5]=%c\n name[6]=%c\n name[7]=%c\n name =%d\n\n",name[0],name[1],name[2],name[3],name[4],name[5],name[6],name[7],name);
printf(" &name[0]=%d\n &name[1]=%d\n &name[2]=%d\n &name[3]=%d\n &name[4]=%d\n &name[5]=%d\n &name[6]=%d\n &name[7]=%d\n name =%d\n",&name[0],&name[1],&name[2],&name[3],&name[4],&name[5],&name[6],&name[7],name);
return 0;
}
実行してみればわかると思いますが
配列要素のそれぞれには1つずつの文字が
それが集合して1つの文字列を成し、
nameはその文字列の先頭アドレスを示す。
つまり
name[0]
のアドレスと
name
のアドレスは同じになると。
わかりましたか?
まだ、アドレスについて勉強した事がなかったら少し難しかったかもしれませんね。
配列はポインタ無しには説明できないので、
もし今理解できなかったらポインタを勉強してから
また後々この回答を見直してみてください。
載せて頂いたプログラム実行しました!!データは全部アドレスを持ってて…と言われてもなかなか実感が湧かないものですが、それを一度でも実際に表示させてみると「なるほーそゆことか!」ってわかるところが凄いです。
がしかし1つ前の回答でdra2jpさんに僕のへっぽこプログラムの謎に対して「わかったらまた言う」と言ってもらったにもかかわらず回答を締め切ってしまいました~すみません(T-T)もしよろしければ是非続きを聞きたかったのですが…締め切りのキャンセルとかできないんでしょうか??それかもう一回トピを立てるしかないのでしょうか…すみません余計な所で迷惑かけてしまって。。
No.4
- 回答日時:
あ、先ほどの回答の一番最後の正解例に要素数6を書き忘れました。
name[1][]
このように要素数を省略できるのは宣言時だけです。
しかしこのような省略はいけません。
#include<stdio.h>
#include<string.h>
int main(){
char name[4][]={"David","Smith","",""};
strcpy(name[2],"suzuki");
strcpy(name[3],"hanako");
printf("[0]=%s\n[1]=%s\n[2]=%s\n[3]=%s\n",name[0],name[1],name[2],name[3]);
return 0;
}
name[2]とname[3]にはいくつ要素をいれていいかわからず、エラーになります。
ですからこの場合
#include<stdio.h>
#include<string.h>
int main(){
char name[4][20]={"David","Smith","",""};
strcpy(name[2],"suzuki");
strcpy(name[3],"hanako");
printf("[0]=%s\n[1]=%s\n[2]=%s\n[3]=%s\n",name[0],name[1],name[2],name[3]);
return 0;
}
このようにしましょう。
要素数は多めに宣言するのが基本です。
回答ありがとうございます!!
No.3の回答がかなり参考になりました☆そして作りたいプログラムも完成しました~ホントにありがとございますm(__)m
それでお言葉に甘えて追加で質問させていただきたいのですが、No.2の回答でも載せました「人物名リストの中から必要な要素を見つける」というプログラムを以下のように書いたのですが、
#include <stdio.h>
int main(void)
{
int i;
char name[5][10]={"David","Mathew","Linda","Pole","Thomas"};
char comp[5]="Pole";
printf("name[0][10] = %s.\n",name[0]);
printf("name[3][10] = %s.\n\n",name[3]);
for(i=0;i<=4;i++){
if(name[i][10]==comp[5]){
printf("Pole is included in this list.\n");
printf("Data number is %d.",i);
}
}
return 0;
}
これを実行すると次のような結果が出ててしまうんです。
name[0][10] = David.
name[3][10] = Pole.
Pole is included in this list.
Data number is 4.
つまり、一致した(if文が成立した)時のiの値は3なのに、その直後にiを出力するとなぜか4が出てきてるんです。
これは一体どうしてなのでしょうか?どうかご回答よろしくお願いします。m(_ _)m
No.3
- 回答日時:
#1,#2さんのおっしゃる事ももっともですが、
ちょっと質問者さんの聞きたい事とずばり同じではないと思うので、回答を書きますね。
まず、初期化同時に文字列を格納できるのは宣言時だけです。
それに文字列はダブルコーテーション「”」で囲みましょう。
例を出します。
int main(){
char name[1][]="David";
return 0;
}
↑これは正解です。宣言時に代入していますから。
int main(){
char name[1][6]="David";
return 0;
}
↑これも正解。なぜ6なのかは文字列の終端に終端記号(ヌル文字)\0 が入るからです。
int main(){
char name[2][]={"David","Mathew"};
return 0;
}
↑これも正解で
int main(){
char name[2][7]={"David","Mathew"};
return 0;
}
↑これも正解です。
しかし以下これは違います。
int main(){
char name[1][];
name[0][]="David";
return 0;
}
int main(){
char name[1][6];
name[1]="David";
return 0;
}
int main(){
char name[1][];
name[1]="David";
return 0;
}
↑これらは全て間違いです。宣言時にしか初期化として格納できません。
もし宣言の後にだいにゅうしたいのでしたら
代入するための関数を使います。
一番最初に
#include<string.h>
を書いて
int main(){
char name[1][];
strcpy(name[0],"David");
return 0;
}
と書きましょう。
strcpy();関数は文字列を代入する関数です。
これを使用する場合はstring.hを最初にインクルードする必要があります。
まだ解らないところがありましたら再度きいてください。
No.2
- 回答日時:
strcpy(name[0],"David");
とかstrncpy を使いましょう
または、不定長の文字列を扱う場合は、
ポインタの配列
char *name[100];
にして
name[0]=strdup("David");
とか
malloc してstrcpy
回答ありがとうございます。すみませんが、先ほど言い忘れてしまったので下の方に対してもここで申し上げます、回答ありがとうございます。
えと、配列に文字列を代入(コピーと言うらしいですね)する方法は分かったのですが、それを複数個作成した場合にfor関数で一括処理できるようにはできないでしょうか?
例えば、
char name-a[]="David";
char name-b[]="Mathew";
char name-c[]="Smith";
という3つの文字列配列があって、これを
char name-x[]="Smith";
と同じ文字列であるかを判別する際に、
for(i=0;i<=2;i++){
if(XXXX==name-x[]){
printf("This list has same data to name-x.");
}
}
とfor文を使って反復命令として実行できないかということです。
(注1)XXXXの所にはname-aからname-cが何らかの形でi=0,1,2によって区別されたものが入る←理想です
(注2)printfの内容はテキトーに考えたのでツッコまないでください。文法もしかりです泣
最初の質問が非常にわかりにくかったようで、すみません。どうかご一考お願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・一回も披露したことのない豆知識
- ・これ何て呼びますか
- ・チョコミントアイス
- ・初めて自分の家と他人の家が違う、と意識した時
- ・「これはヤバかったな」という遅刻エピソード
- ・これ何て呼びますか Part2
- ・許せない心理テスト
- ・この人頭いいなと思ったエピソード
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・あなたの習慣について教えてください!!
- ・ハマっている「お菓子」を教えて!
- ・高校三年生の合唱祭で何を歌いましたか?
- ・【大喜利】【投稿~11/1】 存在しそうで存在しないモノマネ芸人の名前を教えてください
- ・好きなおでんの具材ドラフト会議しましょう
- ・餃子を食べるとき、何をつけますか?
- ・あなたの「必」の書き順を教えてください
- ・ギリギリ行けるお一人様のライン
- ・10代と話して驚いたこと
- ・家の中でのこだわりスペースはどこですか?
- ・つい集めてしまうものはなんですか?
- ・自分のセンスや笑いの好みに影響を受けた作品を教えて
- ・【お題】引っかけ問題(締め切り10月27日(日)23時)
- ・大人になっても苦手な食べ物、ありますか?
- ・14歳の自分に衝撃の事実を告げてください
- ・架空の映画のネタバレレビュー
- ・「お昼の放送」の思い出
- ・昨日見た夢を教えて下さい
- ・ちょっと先の未来クイズ第4問
- ・【大喜利】【投稿~10/21(月)】買ったばかりの自転車を分解してひと言
- ・メモのコツを教えてください!
- ・CDの保有枚数を教えてください
- ・ホテルを選ぶとき、これだけは譲れない条件TOP3は?
- ・家・車以外で、人生で一番奮発した買い物
- ・人生最悪の忘れ物
- ・【コナン30周年】嘘でしょ!?と思った○○周年を教えて【ハルヒ20周年】
- ・10秒目をつむったら…
- ・人生のプチ美学を教えてください!!
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Application.ScreenUpdating = ...
-
VBAでPDFのコピーとリネームを...
-
実行時エラー 3020の対策
-
ACCESS テキストボックスを隙...
-
vbaでxmlからNodeListでデータ...
-
VBA他のブックから値のみ貼付す...
-
コンボボックスのtag情報の取得...
-
C++ コマンドプロンプトでの入...
-
セカンダリDNSが正常かどうか確...
-
2つのpythonがあって、一方で...
-
JSONで文字列が長い時
-
formで特定のinputを送信しない...
-
VB6で、長い時間かかる処理...
-
<SELECT>タグの折り返し
-
文字の横にプルダウンを表示さ...
-
16進の10進変換について
-
Pythonでコンソールをクリアす...
-
セレクトメニューで2つの項目...
-
テーブル内でドロップダウンメ...
-
HASH(0xほげほげ)
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Application.ScreenUpdating = ...
-
実行時エラー 3020の対策
-
VBAでPDFのコピーとリネームを...
-
ACCESS テキストボックスを隙...
-
[python] 文字列を変数名として...
-
構造体の各データの表示につい...
-
FindFirst を複数条件で検索
-
「*:*」って何を意味するのでし...
-
構造体の変数の値を、動的に取...
-
コンボボックスのtag情報の取得...
-
vbaでxmlからNodeListでデータ...
-
phpでボタンを押したときに変数...
-
VBA他のブックから値のみ貼付す...
-
C++ コマンドプロンプトでの入...
-
MSXMLでの属性の存在確認法
-
UWSC:ポップアップウインドウ...
-
エクセルVBA シート名の部分一...
-
【メモリ不足で落ちる(python)】
-
2つのpythonがあって、一方で...
-
use strict;
おすすめ情報