質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
C

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

Q&A

解決済

3回答

1291閲覧

strcpy()の挙動の不具合の原因が知りたいです。

kusakalien

総合スコア11

C

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

1グッド

1クリップ

投稿2019/07/24 18:25

与えられた複数の文字列を辞書順でしてある範囲の単語を表示させるプログラムを作っているのですが
strcpy()を使用している個所から挙動がおかしくなってしまいます。

入力として、与えられるのは
(総単語数:n) (1ページあたりの単語数:k) (何ページ目か:p)
(単語:s[0]) (単語:s[1]) ...
で、
<例>
7 3 2
dog cat bird cow bear rabbit mouse
上記のように与えられます。

上の例の場合ソートした結果、
bear bird cat cow dog mouse rabbit
となるので、
出力は
cow dog mouse
となるのが理想です。

s[0],s1だけソートした結果、
cat
dog
bird
cow
bear
rabbit
mouse
と正常に処理しますが、
s[0],s2だけソートした結果、
bird

dog
cow
bear
rabbit
mouse
となってしまいます、、、

s[1]が消えてしまう原因は何なのでしょうか?
原因が分かる方、ご教授願います。

c

1 2#include <stdio.h> 3#include <string.h> 4#include <stdlib.h> 5 6int main(void){ 7 8 char str[100], *ch, *s[1000], tmp[]="unkooooooo"; 9 int n=0, k=0, p=0, i=0, j=0, min=0; 10  //入力の処理 11 fgets(str, sizeof(str), stdin); 12 ch = strtok(str, " \n"); 13 n = atoi(ch); 14 ch = strtok(NULL, " \n"); 15 k = atoi(ch); 16 ch = strtok(NULL, " \n"); 17 p = atoi(ch); 18 //printf("%d %d %d\n", n, k, p); 19 fgets(str, sizeof(str), stdin); 20 ch = strtok(str, " \n"); 21 s[0] = ch; 22 for(i=1; i<n; i++){ 23 ch = strtok(NULL, " \n"); 24 s[i] = ch; 25 } 26 //for(i=0; i<n; i++){ 27 //printf("%s\n", s[i]); 28 //} 29 30 //ソート 31 for(i=0; i<n; i++){ 32 for(j=i+1; j<n; j++){ 33 //for(j=0; j<n-1; j++){ 34 if(strcmp(s[i], s[j])>0){ 35 //printf("1"); 36 //strcpy(tmp, "unkooooooo"); 37 //printf("%s\n", tmp); 38 strcpy(tmp, s[i]); 39 strcpy(s[i], s[j]); 40 strcpy(s[j], tmp); 41 } 42 } 43 //for(i=0; i<n; i++){ 44 // printf("%s\n", s[i]); 45 //} 46 } 47 /* 48 i=0; 49 j=1; 50 //for(j=0; j<n-1; j++){ 51 if(strcmp(s[i], s[j])>0){ 52 //printf("1"); 53 //strcpy(tmp, "unkooooooo"); 54 //printf("%s\n", tmp); 55 strcpy(tmp, s[i]); 56 strcpy(s[i], s[j]); 57 strcpy(s[j], tmp); 58 } 59 60 i=0; 61 j=2; 62 //for(j=0; j<n-1; j++){ 63 if(strcmp(s[i], s[j])>0){ 64 //printf("1"); 65 //strcpy(tmp, "unkooooooo"); 66 //printf("%s\n", tmp); 67 strcpy(tmp, s[i]); 68 strcpy(s[i], s[j]); 69 strcpy(s[j], tmp); 70 } 71 */ 72   73 if(k*p > n) 74 min = n; 75 else 76 min = k*p; 77 78 //出力 79 for(i=k*(p-1); i<min; i++){ 80 //for(i=0; i<n; i++){ 81 printf("%s\n", s[i]); 82 } 83 84 return 0; 85}
set0gut1👍を押しています

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

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

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

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

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

guest

回答3

0

入れ替えのところでstrcpyしているのが原因でしょう。
配列sは、char型のポインタの配列です。
文字列の配列ではないです。
strtok関数の戻り値を代入しているのでわかりますよね。
その前提で考えれば、入れ替え処理は単なる値の交換とすればよいということにたどり着くはずです。

c

1tmp = s[i]; 2s[i] = s[j]; 3s[j] = tmp;

投稿2019/07/24 23:52

ttyp03

総合スコア16996

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

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

0

ベストアンサー

strcpyのオーバーフローですね。

再現コード

c

1#include <stdio.h> 2#include <string.h> 3 4int main(void){ 5 char foo[] = "foo"; // メモリ上の連続した領域に何個か作る 6 char bar[] = "bar"; 7 char baz[] = "baz"; 8 char xxx[] = "123456"; 9 strcpy(bar, xxx); 10 printf("foo: %s\nbar: %s\nbaz: %s\n", foo, bar, baz); 11 return 0; 12}

出力

foo: 56 bar: 123456 baz: baz

上のコードではbarにstrcpyした文字列が入り切らないためfooまで侵食してて挙動が壊れてます。

質問者さんの遭遇した状況でいうと

s[0],s2だけソートした結果、
bird

dog

このときにbirdの末尾のヌル文字がcatの0文字目を侵食して、空文字列として認識されるようになっているという挙動です。

質問者さんのコードへの変更としては、tmpをchar*型変数にして

char str[100], *ch, *s[1000], *tmp;

スワップをstrcpyではなくポインタの代入で済ませれば

tmp = s[i]; s[i] = s[j]; s[j] = tmp;

この課題については正しい出力をするようになります。

投稿2019/07/24 19:13

編集2019/07/24 19:45
set0gut1

総合スコア2413

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

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

kusakalien

2019/07/25 09:04

原因も分かり、課題も解決できました!! ありがとうございました。 他の回答者さんもありがとうございました。
guest

0

dog cat bird cow bear rabbit mouseの場合
s[0]が&str[0]でs[1]が&str[4]でs[2]が&str[8]だからです。

|s[0]||||s[1]||||s[2]|||||
|:--:|:--:|:--:|
|d|o|g|\0|c|a|t|\0|b|i|r|d|\0|
|c|a|t|\0|d|o|g|\0|b|i|r|d|\0|
|b|i|r|d|\0|a|t|\0|d|o|g|\0|\0|

sをchar s[100][100]と2次元配列で定義し
s = strtok(str, "\n");

strcpy(s, strtok(str, "\n"));
にしていくとよいのではないかと思います。

投稿2019/07/24 19:11

asm

総合スコア15147

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問