
aizu online judgeというサイトの9Bの問題に関する質問です。scanfで文字数を読み取り、strncpyでその文字数分コピーするということをしているのですが、三回目の読み取りで1を入力するとなぜか二文字コピーされてしまいます。いろいろ検証してみましたが原因がよくわかりません。どなたか教えてください。よろしくお願いします。
問題文 (https://onlinejudge.u-aizu.ac.jp/courses/lesson/ …
シャッフル
1つのアルファベットが描かれた n 枚のカードの山をシャッフルします。
1回のシャッフルでは、下から h 枚のカードをまとめて取り出し、それを残ったカードの山の上に積み上げます。
カードの山は以下のように1つの文字列で与えられます。
abcdeefab
最初の文字が一番下にあるカード、最後の文字が一番上にあるカードを示しています。
例えば、これを h が 4 でシャッフルすると、最初の4文字 abcd が、残りの文字 eefab の末尾へ連結されるので以下のようになります:
eefababcd
このシャッフルを何回か繰り返します。
カードの山の最初の並び(文字列)と h の列を読み込み、最後の並び(文字列)を出力するプログラムを作成して下さい。
自分の書いたコード
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main()
{
char a[201], b[201];
int m;
int h;
int n=0;
while(1) {
scanf("%s", a);
if(a[0]=='-') break;
scanf("%d", &m);
for(int i=0; i<m; i++) {
scanf("%d", &h);
strncpy(b, a+n, h);
printf("%s\n", b); //配列bの状況を確認するために入れました。
strcat(a, b);
n+=h;
}
printf("%s", a+n);
putchar('\n');
}
}
No.1ベストアンサー
- 回答日時:
(1) strncpy のマニュアルをよく読んでください。
おそらく「指定した長さの文字列のコピー」という点を勘違いしています。
(2)そもそも、現在のプログラムには致命的な問題があります。
(1)について。
例)
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/ …
> 警告: src の最初の n バイトの中にヌルバイトがない場合、 dest に格納される文字列はヌルで終端されないことになる。
strncpy(b, a+n, h);
a={'a','b','c','d','e','\0'}
n=0
h=3
とすると、これを実行後
b={'a','b','c'}
となります。
「a の最初の 3 バイトの中にヌルバイトがない」ので「b に格納される文字列はヌルで終端されないこと」になります。
b[3]以降はstrncpy実行前のままです。'\0' である保証はありません。
strcat(a, b);
上記に続けて実行すると、bの「終わり」がはっきりしないので
a={'a','b','c','d','e','a','b','c'}
までは確実ですが、その後がどこまで続くかわかりません。
おそらく「配列bが0でクリアされた状態で始まる」ような設定(例えばデバッグモード)でコンパイルしたため、以下のように動作しているのでしょう。
a="aabc"
h=1→ b={'a' ,0,0,...} /* たまたま b[1]=0だったので "a"と解釈される */→ a+n="abca"
h=2→ b={'a' ,'b' , 0,0,...} /* たまたま b[2]=0だったので "ab"と解釈される */ → a+n="caab"
h=1→ b={'c' ,'b' ,0,0,...} /* b[0]に'c'がコピーされたが、前の b[1]='b'が残ってるので "cb"と解釈される */→ a+n="aabcb"
本来は(初期化しなければ)中身がどうなっているか決まってないのがC言語です。
最初のh=1の段階で
a+n="abcakopasj-0gajpadj-afspf2^09=UJAH0HFAS"
などとなってもおかしくありません。
文字列として扱いたいのなら、strmcpyの後に'\0'を明示的に設定する必要があります。
(2) strncpyなどどうでもよくなるような欠陥があります。
シャフルするときに、配列aの後にstrcatで付けたすようになっていますが、
strcatは配列の容量を増やしたりはしません。
付けたしていって200文字を越えたら、a[201]での範囲を越えていきます(バッファオーバーラン)
・a:200文字
・h=199
とすると、strcatによって 399文字の文字列が作られます。
完全にa[201]をオーバーしてます。
仕様によると、最大100回操作するので
このままでは aは200+199*100文字の文字列になる可能性があります。
それだけの長さの配列を用意する、という手段もありますが、
今のa[201],b[201]のまま、やり方を変えるのがいいのでは、と思います。
回答ありがとうございます!マニュアルをよく読んでみます。また(2)の点についても指摘していただきありがとうございました。助言していただいた通りに、a[201],b[201]のまま他のやり方を考えてみます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# str[j++]の意味 2 2022/08/30 16:20
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
16進数を2文字ずつ配列に格納し...
-
_tcscpy_s(wcscpy_s)の第二引数...
-
プログラムによく出てくるst...
-
C++で入力した文字列から数字を...
-
char型配列の最大要素数
-
%dなどの違い
-
プログラム問題・・・
-
VB6.0でのバイナリデータの扱い...
-
Shift_JIS(16進)を文字に変換す...
-
C言語のコンパイル時に表示され...
-
文字列操作
-
nullと""、\\0とEOFの違いにつ...
-
int型での文字列の扱いについて
-
VBA-DLLの引数受け渡しについて
-
TCL言語で文字列検索方法を教え...
-
C#でstringをポインタとして渡す
-
[C++]WCHARの1文字目しか表示で...
-
C言語の基礎
-
曜日を格納する配列の大きさ
-
ソースコードの間違い (C言語)
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
TCL言語で文字列検索方法を教え...
-
C#でstringをポインタとして渡す
-
C++で入力した文字列から数字を...
-
nullと""、\\0とEOFの違いにつ...
-
c#で他のアプリの文字入力フォ...
-
WSH(VBS)でJSONの文字列を読み...
-
バイナリファイル中の日本語文...
-
シリアル通信で0x00を送信した...
-
%dなどの違い
-
16進数を2文字ずつ配列に格納し...
-
VB6.0でのバイナリデータの扱い...
-
C++で文字列の右端から特定の文...
-
構造体→文字列→構造体 をする方法
-
_tcscpy_s(wcscpy_s)の第二引数...
-
char型配列の最大要素数
-
VBA-DLLの引数受け渡しについて
-
binaryに対して正規表現を適用...
-
数字の入った配列をファイルへ...
-
C言語の課題で困っています;
-
プログラムによく出てくるst...
おすすめ情報