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

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

詳細はこちら
C

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

Q&A

解決済

2回答

6880閲覧

Aizu Oneline JudgeでRunがうまくいかない

Courange

総合スコア17

C

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

0グッド

0クリップ

投稿2019/10/22 14:31

前提・実現したいこと

Aizu oneline judgeの問題Lesson - ITP1 ITP1_6_BでRunがうまくいきません・・・

発生している問題・エラーメッセージ

Runがで引っかかっている感じです

<エラーメッセージ>
timeout: the monitored command dumped core 0.00user 0.00system 0:00.01elapsed 7%CPU (0avgtext+0avgdata 2100maxresident)k 8inputs+32outputs (0major+182minor)pagefaults 0swaps

該当のソースコード

C

1#include<stdio.h> 2int main (){ 3 int card[4][13]; 4 int n,d,i,j; 5 char c; 6 7 scanf("%d",&n); 8 9 for (j = 0;j < n; ++j){ 10 scanf(" %c %d",&c,&d); 11 if (c == 'S'){ 12 card[1][d] = 1; 13 } 14 if (c == 'H'){ 15 card[2][d] = 1; 16 } 17 if (c == 'C'){ 18 card[3][d] = 1; 19 } 20 if (c == 'D'){ 21 card[4][d] = 1; 22 } 23 } 24 25 for (i = 1; i <= 4; ++i){ 26 for (j = 1; j <= 13; ++j){ 27 if (card[i][j] != 1){ 28 if (i == 1){ 29 printf("S %d\n",j); 30 } 31 if (i == 2){ 32 printf("H %d\n",j); 33 } 34 if (i == 3){ 35 printf("C %d\n",j); 36 } 37 if (i == 4){ 38 printf("D %d\n",j); 39 } 40 } 41 } 42 } 43 44 return 0; 45}

試したこと

自分の環境では以下のことを試しましたがなぜD 2が抜けているのかわからない状況です。

input

14 2S 1 3H 1 4C 1 5D 1

output

1S 2 2S 3 3S 4 4S 5 5S 6 6S 7 7S 8 8S 9 9S 10 10S 11 11S 12 12S 13 13H 2 14H 3 15H 4 16H 5 17H 6 18H 7 19H 8 20H 9 21H 10 22H 11 23H 12 24H 13 25C 2 26C 3 27C 4 28C 5 29C 6 30C 7 31C 8 32C 9 33C 10 34C 11 35C 12 36C 13 37D 3 38D 4 39D 5 40D 6 41D 7 42D 8 43D 10 44D 11 45D 12 46D 13

補足情報(FW/ツールのバージョンなど)

OS:Windows 10 Home
実行環境:学習用C言語開発環境

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

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

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

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

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

guest

回答2

0

エラーメッセージはちゃんと読みましょう。まぁ、読んですぐわかるような書き方かというとそうでも無いですけど、でもそれを読まなければ問題の解決は遠のきます。
dumped coreと言っています。C/C++をいじる人はこの現象を知っておく必要があります。メモリの内容の破壊があって、プログラムを続行出来なくなった時に不具合解析のためにメモリイメージのデータを書き出すことで、俗に「コアを吐く」とか言ったりもしますが、とにかくメモリ操作に間違いがあるということ。アクセスしてはいけない領域にアクセスしてるとか。

で、プログラムを見ると...
Cでは、N要素の配列のインデックス(添字)は0~N-1のN個です。
例えば、
int a[10];
ではa[0],a[1],...a[9]の10要素が確保されます。で、a[10]にアクセスしたときの動作は未定義です。何が起こっても文句は言えません。とりあえず、今回はコアダンプになったようです。

関係ないですが、私は学習用C言語開発環境(EasyIDEC)はお勧めしません。
・広告を仕込む仕組みが古くなってエラーが出るのに放置されていること
・Cの規格が古いこと。学習用には十分、という言い方も出来ますが、しかし参考にしようとしたプログラムがエラーで動かない、という現象も起こります。
・日本語対応が出来ていなくて、一部の文字を使うとエラーになることがある(Shift JISの\5c問題)こと

どうしてもこれがいいんだ、というなら止めはしませんが。

投稿2019/10/22 14:53

thkana

総合スコア7703

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

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

Courange

2019/10/22 15:19

ありがとうございます。 実はエラーメッセージの内容が一切わからない状態でここで質問しました・・・ いままでは全部グーグル検索で何とかしていたのですがこのエラーメッセージってどこ検索すればいいのかよくわからなくて・・・ あと開発環境について、とりあえず「C言語 開発環境」といった感じでグーグル検索をかけるつもりですが、なにかおすすめのサイトなり、開発環境があったら教えてくださると助かります。
thkana

2019/10/22 15:37

最近はVisualStudio Code + MinGWが流行りな気がします。 VisualStudio Community(Codeではない)はプロには便利でも初心者にはちょっと使い切れない、という面があるような。 学習用C言語開発環境程度のものでいいなら、Code:blocksとか良さそうかな、と私は思いますが、日本語化には難があるようです。メニューのSaveが「保存」じゃなきゃ嫌だ、という方にはおすすめしません。
Courange

2019/10/22 16:16

VisualStudio Communityは私も入れてい放置している感じです・・・(使い方がよくわからないという感じで・・・)。こちらでも別のコメントでも本当にありがとうございましたm(__)m
guest

0

ベストアンサー

問題点1

配列の使い方を間違えています。
例えば、この部分は見るからにおかしいです。

C

card[4][d] = 1; // int card[4][13] と宣言されているので、card[4]にはアクセスできない

プログラム後半のfor文でも同じようなミスが見受けられます。


n要素の配列にアクセスする際、添え字は 0~n-1 を使います。
つまり初期化済みの int arr[3] に対して次は合法ですが、

C

1for(int i = 0; i < 3; ++i) { 2 printf("%d, %d\n", i, arr[i]); 3}

次は違法です。

C

1for(int i = 1; i <= 3; ++i) { 2 printf("%d, %d\n", i, arr[i]); 3}

後者のコードのような範囲外アクセスは未定義動作を引き起こします。
実行環境に依って動作に差異が出ても何ら不思議ではありません。

問題点2

C

if (card[i][j] != 1){

ご提示のコードを書く際、一つ思い込みをしているように思います。
『配列の要素は、最初から何らかの数で埋められているのだ』... 残念ながら、それは間違いです。

次のように実際に試してみることができます。

C

1#include <stdio.h> 2 3int main(void) { 4 int arr[10]; 5 for(int i = 0; i < 10; ++i) { 6 printf("%d\n", arr[i]); 7 } 8 9 return 0; 10}

実行結果 Wandbox

0 0 0 0 4195600 0 4195328 0 787312336 32767

実行結果は毎回変わり得ます。それこそ全部1になってもおかしくありません。
そもそも実行できる保証もありませんが。


ともかく、次のように明示的に初期化してやる必要があります。

C

1int card[4][13] = {0};

投稿2019/10/22 14:48

編集2019/10/22 14:57
LouiS0616

総合スコア35668

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

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

Courange

2019/10/22 14:56

ありがとうございました。 何とかRunは抜け出したのですが・・・Result Checkで引っかかりました(´・ω・`) これって別でもう一回質問立て直したほうがいいですか?
LouiS0616

2019/10/22 14:58

card[~][13] もアクセスできないのですが、そのあたりも修正しましたか?
LouiS0616

2019/10/22 14:59

現時点ではまだ新規の質問は要らないように思います。
thkana

2019/10/22 15:10

問題点2の方の話じゃないかと>引っかかる (自動で初期化されないのは配列かどうかじゃなくて(動的な)ローカル変数だからですが。静的な変数は(配列を含め)特に指示しない場合0に初期化されることが保証されます...というのは「とりあえず初期化しておけ」ということで敢えて細かく言わなかったのでしょうか)
LouiS0616

2019/10/22 15:25 編集

@thkana さん > 自動で初期化されないのは ~ 敢えて細かく言わなかったのでしょうか 静的・動的関わらず、明示的に初期化する習慣を付けるのが特に初心者にとっては有用かと思います。 ...というのは建前で、そこまで考慮していなかったです。 配列に限った話だと強調するような意図もありませんでしたが、確かにそのように受け取られかねない記述かもしれません。 thkanaさんのコメントをもってその辺りの穴が補完された、ということにさせて下さい。 ご指摘ありがとうございます。
Courange

2019/10/22 15:29

```c #include<stdio.h> int main (){ int card[5][14];//修正点 int n,d,i,j; char c; scanf("%d",&n); for (j = 0;j < n; j++){ 省略 } for (i = 1; i <= 4; i++){ 省略 } return 0; } ``` という感じになりました あとちょっと本題からずれるのですが動的なローカル変数とはmallocを用いて作る配列などという認識で合っていますか?
LouiS0616

2019/10/22 15:34

for (i = 1; i <= 4; i++){ がまずいのでは?
LouiS0616

2019/10/22 15:37 編集

> 動的なローカル変数とはmallocを用いて作る配列などという認識で合っていますか? ブロック内で普通に宣言した変数だと思って下さい。 静的なローカル変数を宣言したい場合static指定子を用います。
Courange

2019/10/22 15:48

動的なローカル変数については理解しました。 ですが、 >for (i = 1; i <= 4; i++){ がまずいのでは? card[0]もcard[5]も使ってないないので大丈夫だと思っていたのですが・・・ 一応この部分をのせます for (i = 1; i <= 4; i++){ for (j = 1; j <= 13; j++){ if (card[i][j] != 1) { if (i == 1){ printf("S %d\n",j); } if (i == 2){ printf("H %d\n",j); } if (i == 3){ printf("C %d\n",j); } if (i == 4){ printf("D %d\n",j); } } } }
LouiS0616

2019/10/22 15:50

card[4] にアクセスしている時点でアウトです。 card[0] から card[3] までしか使えません。
Courange

2019/10/22 15:57

私の勘違いだとしてら申し訳ないのですが card[5][14]; と宣言しているのに card[0]からcard[3]までしか使えないのですか?
thkana

2019/10/22 15:58

int card[5][14];//修正点 だそうですからセーフでは。 しかし...プログラムとしては「駄目ではない」のですが、card[0][0]...card[0][13]とかcard[1][0], card[2][0]とかが使われず無駄になります。今どきのメモリが有り余ったPC上でならそれくらいは問題ないとも言えますが、配列が大きくなるような場合にはその方針はちょっと考えたほうがいいかも知れません。 C/C++プログラマの間の常識としては、for(i=1;i<=N;i++)というループは「あれれ?」と思われるものと考えて下さい。普通は、for(i=0;i<N;i++)で、card[1][d-1] = 1;とかprintf("S %d\n",j+1);とかして辻褄合わせをするでしょう。 --- 静的というのは「プログラムが始まってから終わるまで存在する」もの、一方「プログラムの途中で出来たり無くなったりする」のが動的です。 mallocで確保した領域は、mallocが実行されるまでは無いので動的ですし、関数の中で宣言する変数も、関数が実行されていない間は存在しないので動的です。キモチとしては、プログラムが始まる時(というか始まる前)は多少手間をかけて初期化してもいいけど、プログラムの実行中は初期化の少しの手間も惜しむ、というところですね。
Courange

2019/10/22 16:06

あと配列を宣言するときに0を代入するのを忘れていました・・・ 0を代入することで正解できました!
LouiS0616

2019/10/22 22:44

@Courange さん > 私の勘違いだとしてら申し訳ないのですが いや、おっしゃるとおりです。 分かり良いようにコメントまで入っていたのにすっかり見逃してしまいました。失礼しました。 解決したようで何よりです。 @thkana さん 有用なコメントを寄せていただきありがとうございます。 今後ももし間違い・あるいは気になる点がありましたら、ご教示いただけると幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問