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

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

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

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

544閲覧

文字数が異なる文字列を織り交ぜたい

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2022/05/18 13:02

編集2022/05/18 13:06

以下のように動くプログラムを作っています。
<例1>Tokyo + Roma→TRookmyao
<例2>Roma + Empire →REommpaire
例2のように、長い方の文字列の余った部分は生成する文字列の後ろに連結させます。

引数のa,bは文字列で、dは生成する配列へのポインタです。
しかし、以下のコードだと例2のケースがSegmentation Faultになってしまいます。
これを回避して正常に動作させたいです。よろしくお願いします。

C++

1#include <stdio.h> 2#include <string.h> 3 4char d[200]; 5 6void interleave(char* a, char* b, char* d){ 7 d[0] = a[0]; 8 d[1] = b[0]; 9 10 //iは配列d用の変数、jは配列b用の変数 11 if(strlen(a) > strlen(b)){ 12 for(int i = 2; a[i/2] != '\0'; i+= 2){ 13 int j = 1; 14 d[i] = a[i/2]; 15 d[i+1] = b[j]; 16 j++; 17 } 18 } 19 20 if(strlen(b) > strlen(a)){ 21 int j = 1; 22 23 for(int i = 2; b[j] != '\0'; i += 2){ 24 d[i] = a[i/2]; 25 d[i+1] = b[j]; 26 j++; 27 } 28 29 int f = strlen(a);//文字数が少ない方の文字数を計算 30 for(int i = f * 2; b[f] != '\0'; i++){ 31 d[i] = b[f];//余った文字列を連結 32 } 33 } 34 35 int e = strlen(a) + strlen(b); 36 d[e] = '\0'; 37} 38 39int main(){ 40 interleave("INIAD", "Toyo", d); 41 printf("%s\n", d); 42 interleave("Toyo", "University", d); 43 printf("%s\n", d); 44 return 0; 45}

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

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

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

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

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

thkana

2022/05/18 13:11

> なってしまいます そうですね。だからどうしろと? いや、もちろん正解を示せということなのでしょうけれど、 掲示板は間違ったプログラムを投げると自動で正解を出してくれる自動システムではないのですから、 もう少し言いようというものがあると思うのですが。 すくなくともその事象について「動作をトレースしてみたがどうしても期待する結果がでるはずで間違いが見つからない」みたいな話はあるべきじゃないかと思ったりするのですが。
退会済みユーザー

退会済みユーザー

2022/05/18 14:00

そうですね。失礼しました。現在は修正されています。 あとプログラムの挙動を細かく説明していただいてありがとうございました。 とても理解が捗りました。
guest

回答3

0

ベストアンサー

短いコードですから、まずはデバッグビルドして、デバッガでステップ実行してみれば問題がわかるかと思います。


c

1 if(strlen(a) > strlen(b)){ 2 for(int i = 2; a[i/2] != '\0'; i+= 2){

c

1 if(strlen(b) > strlen(a)){ 2 int j = 1; 3 for(int i = 2; b[j] != '\0'; i += 2){

長い方の入力の終端までループすると、短い方は終端を超えてアクセスしてしまいます。

c

1 for(int i = f * 2; b[f] != '\0'; i++){ 2 d[i] = b[f];//余った文字列を連結 3 }

ループ中で f が変化しないので、このループはひたすら増加するid[i]に書き込んでいきます。

投稿2022/05/18 13:31

編集2022/05/18 13:36
int32_t

総合スコア20872

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

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

退会済みユーザー

退会済みユーザー

2022/05/18 13:50

教えていただいてありがとうございます。 for(int i = f * 2; b[f] != '\0'; i++){ d[i] = b[f]; f++; } としたら正しく動きました。
int32_t

2022/05/18 14:02 編集

そこは strcpy(d + f * 2, b + f); と書くとよりシンプルですね。 あと、そこだけ直しても正しくは動きませんよ。回答前半の問題も直さないと。 interleave("University", "Toyo", d); をやると結果がおかしいはずです。
guest

0

これくらいのことはやってみてから質問して欲しいなぁ。

C

1//説明の都合上行番号をつけてみた 201: void interleave(char* a, char* b, char* d){ 302: d[0] = a[0]; 403: d[1] = b[0]; 504: 605: //iは配列d用の変数、jは配列b用の変数 706: if(strlen(a) > strlen(b)){ 807: for(int i = 2; a[i/2] != '\0'; i+= 2){ 908: int j = 1; 1009: d[i] = a[i/2]; 1110: d[i+1] = b[j]; 1211: j++; 1312: } 1413: } 1514: 1615: if(strlen(b) > strlen(a)){ 1716: int j = 1; 1817: 1918: for(int i = 2; b[j] != '\0'; i += 2){ 2019: d[i] = a[i/2]; 2120: d[i+1] = b[j]; 2221: j++; 2322: } 2423: 2524: int f = strlen(a);//文字数が少ない方の文字数を計算 2625: for(int i = f * 2; b[f] != '\0'; i++){ 2726: d[i] = b[f];//余った文字列を連結 2827: } 2928: } 3029: 3130: int e = strlen(a) + strlen(b); 3231: d[e] = '\0'; 3332:}

"Roma"と"Empire"を与えたとして
02:でd[0]='R'
03:でd[1]='E'
strlen(a)<strlen(b)だから15行目まで飛んで (別件だけどstrlen(a)==strlen(b)だったら何が起こる?)
16: j=1
18:ループに入ってi=2,j=1
19: d[2]=a[1];a[1]は'o'
20: d[3]=b[1];b[1]は'm'
21: jは2になる
18: i+=2でiは4 b[2]は'p'だからループ継続
19: d[4]=a[2]; a[2]は'm'
20: d[5]=b[2]; b[2]は'p'
21: jは3になる
18: i+=2でiは6 b[3]は'i'だからループ継続
19: d[6]=a[3]; a[3]は'a'
20: d[7]=b[3]; b[3]は'i'
21: jは4になる
18: i+=2でiは8 b[4]は'r'だからループ継続
19: d[8]=a[4]; a[4]は'\0' (これ以上このループを続けるのに意味がある?)
20: d[9]=b[4]; b[4]は'r'
21: jは5になる
18: i+=2でiは10 b[2]は'p'だからループ継続
19: d[10]=a[5]; a[5]は未定義
20: d[11]=b[5]; b[5]は'e'
21: jは6になる
18: i+=2でiは12 b[6]は'\0'だからループ終了

24: fは"Roma"の文字数だから4
25:ループに入ってi=8, b[4]は'r'
26:d[8]=b[4]
25:iは9 , b[4]は'r'でループ継続
26:d[9]=b[4]
25:iは10 , b[4]は'r'でループ継続
26:d[10]=b[4]
<略>
25:iは200 , b[4]は'r'でループ継続
26:d[200]=b[4] ただしd[200]は未定義
25:iは201 , b[4]は'r'でループ継続
26:d[201]=b[4] ただしd[201]は未定義
以下続く。

投稿2022/05/18 13:42

編集2022/05/18 14:09
thkana

総合スコア7639

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

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

thkana

2022/05/18 13:50

> これを回避して正常に動作させたい プログラムの動作を追ってみれば、「それ」だけを回避しても正常には動作しない、というのがわかりますよね。
退会済みユーザー

退会済みユーザー

2022/05/18 13:51

教えていただいてありがとうございます。 for(int i = f * 2; b[f] != '\0'; i++){ d[i] = b[f]; f++; } としたら正しく動きました。
thkana

2022/05/18 14:11

結果だけみないで、途中に「未定義」のアクセスがあるという事実を重視してください。いわば地雷、いつ爆発してもおかしくないバグです。 Cでは「一見動いたようにみえる」だけで実はやってはいけないことが行われているというのはよくあることです。
guest

0

Segmentation Faultになるってことは、不正な領域に読み書きを行った、ということですんで、
まずは配列の範囲外になるところを探そう

投稿2022/05/18 13:18

y_waiwai

総合スコア87774

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問