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

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

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

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

Visual Studio Code

Visual Studio Codeとは、Microsoft社が開発したマルチプラットフォーム対応のテキストエディタです。Visual Studioファミリーの一員でもあります。拡張性とカスタマイズ性が高く、テキストエディタでありながら、IDEと遜色ない機能を備えることができます。

Q&A

解決済

2回答

706閲覧

Cにおける、2 次元配列に格納した文字列の検索・入れ替えプログラムの作成

henta-e

総合スコア1

C

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

Visual Studio Code

Visual Studio Codeとは、Microsoft社が開発したマルチプラットフォーム対応のテキストエディタです。Visual Studioファミリーの一員でもあります。拡張性とカスタマイズ性が高く、テキストエディタでありながら、IDEと遜色ない機能を備えることができます。

0グッド

0クリップ

投稿2023/10/24 09:04

編集2023/10/24 11:45

実現したいこと

2 次元配列に格納された文字列の検索・入れ替えを行うプログラムを作成。

前提

c言語に関する質問です。
上記を実現するためのソースコードを作成したのですが、理想通りの実行結果にならないのでアドバイスお願いします。

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

./a.out 0: Yokosuka 1: Chigasaki 2: Fujisawa 3: Yokohama 4: Hiratsuka 5: Sagamihara 処理の入力(1: 検索 2: 入れ替え 0: 終了)> 2 一つ目の位置の入力> 1 二つ目の位置の入力> 3 0: Yokosuka 1: Yokohama Fujisawa  :⑴ 2: Fujisawa 3: Chigasaki 4: Hiratsuka 5: Sagamihara 処理の入力(1: 検索 2: 入れ替え 0: 終了)> ⑴が問題の部分です。 列の入れ替えを行った際、なぜか変な位置に配列内の文字が表示される。

該当のソースコード

C

1#include <stdio.h> 2#include <string.h> 3 4#define WLEN 20 5#define WNUM 6 6 7int main() { 8 char words[WNUM][WLEN] = {"Yokosuka", "Chigasaki", "Fujisawa", 9 "Yokohama", "Hiratsuka", "Sagamihara"}; 10 int command; /* 選択処理管理用変数 */ 11 12 /* 変数宣言の追加 */ 13 char search[WLEN]; 14 int pos1, pos2, i, j, match; 15 16 while (1) { 17 printf("\n"); /* 文字列(2次元配列)の出力が見やすいように1行空白行を出力 */ 18 19 /* 文字列(2次元配列)の出力) */ 20 for (i = 0; i < WNUM; i++) { 21 printf("%d: %s\n", i, words[i]); 22 } 23 /* コマンドの入力 */ 24 printf("\n処理の入力(1: 検索 2: 入れ替え 0: 終了)> "); 25 scanf("%d", &command); 26 27 switch (command) { 28 case 1: /* 検索処理 */ 29 printf("検索文字列の入力> "); 30 /* 標準入力からの検索文字列の読み込み */ 31 scanf("%s", search); 32 /* 文字列の検索処理 */ 33 for (i = 0; i < WNUM; i++) { 34 match = 0; 35 for (j = 0; j < WLEN - strlen(search); j++) { 36 if (words[i][j] == search[0]) { 37 match = 1; 38 for (int k = 1; k < strlen(search); k++) { 39 if (words[i][j + k] != search[k]) { 40 match = 0; 41 break; 42 } 43 } 44 if (match == 1) { 45 printf("%d 番目の文字列の%d文字目から一致\n", i, j + 1); 46 } 47 } 48 } 49 } 50 break; 51 case 2: /* 入れ替え処理 */ 52 printf("一つ目の位置の入力> "); 53 /* 標準入力からの一つ目の位置の読み込み*/ 54 scanf("%d", &pos1); 55 56 printf("二つ目の位置の入力> "); 57 /* 標準入力からの二つ目の位置の読み込み */ 58 scanf("%d", &pos2); 59 /* 文字列の入れ替え処理 */ 60 char temp[WLEN]; 61 62 int len1 = strlen(words[pos1]); 63 int len2 = strlen(words[pos2]); 64 int len = (len1 < len2) ? len1 : len2; 65 char ch; 66 67 for (int i = 0; i < len; i++) { 68 ch = words[pos1][i]; 69 70 words[pos1][i] = words[pos2][i]; 71 words[pos2][i] = ch; 72 } 73 74 if (len1 != len2) { 75 char *longer; 76 char *shorter; 77 78 if (len1 > len2) { 79 longer = words[pos1]; 80 shorter = words[pos2]; 81 } else { 82 longer = words[pos2]; 83 shorter = words[pos1]; 84 } 85 for (i = len; i < WLEN; i++) { 86 shorter[i] = longer[i]; 87 longer[i] = ' '; 88 } 89 } 90 break; 91 case 0: /* 処理の終了 */ 92 printf("\n"); 93 return 0; 94 break; 95 } 96 } 97 98 return -1; 99} 100

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

VScode (最新ver)

ここにより詳細な情報を記載してください。

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

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

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

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

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

jimbe

2023/10/24 09:54 編集

非情に細かいことですが、"該当のソースコード" の一行目の「ソースコード」は削除したほうが良いと思います。 また、コードのマークダウン内での丸付き数字は非常に見辛いですので、せめて"(1)"とかにしては如何でしょうか。
jimbe

2023/10/24 10:34 編集

36 行目の `WLEN - strlen(search)` というのは何でしょう。 strcmp とか strstr は使ってはいけない縛りでしょうか。 47 行目の break は何の為にあるのでしょうか。 文字列は '\0' で終わるということはお分かりでしょうか。
hoshi-takanori

2023/10/24 10:16

> コードのマークダウン内での丸付き数字は非常に見辛い そんなことないと思いますけど。
henta-e

2023/10/24 11:37

>非情に細かいことですが、"該当のソースコード" の一行目の「ソースコード」は削除したほうが良いと思います。 また、コードのマークダウン内での丸付き数字は非常に見辛いですので、せめて"(1)"とかにしては如何でしょうか。 ありがとうございます。今後質問する際の参考にさせていただきます。
henta-e

2023/10/24 11:40

>36 行目の `WLEN - strlen(search)` というのは何でしょう。 strcmp とか strstr は使ってはいけない縛りでしょうか。 自分の知識の範囲内で作成した結果です。特に縛りがあるわけではありません。 >47 行目の break は何の為にあるのでしょうか。 改めてみたら不用でした!該当部分のbreakを削除して再実行したら①の不具合が治りました。ご指摘いただきありがとうございます。 >文字列は '\0' で終わるということはお分かりでしょうか。 存じ上げております。
jimbe

2023/10/24 17:35 編集

編集ありがとうございます。 目の疲れと老眼のせいだとは思います (><;;;;
guest

回答2

0

文字列が繋がってしまうのは、 文字列終端の \0 を上書きするようにスペースにしてしまっているからでしょう。
入れ替えは、文字列の入っている領域の大きさは WLEN と決まっています(そして何万文字とかでは無い)ので、その領域内を丸ごと入れ替えてしまうのが簡単です。

c

1 /* 文字列の入れ替え処理 */ 2 for(int i=0; i<WLEN; i++) { 3 char c = words[pos1][i]; 4 words[pos1][i] = words[pos2][i]; 5 words[pos2][i] = c; 6 }

検索も、 strstr 関数(とポインタ)が扱えればかなり短くなります。
strstr は、第一引数の文字列から第二引数の文字列を探します。見つかればその位置(アドレス)を返し. 見つからなければ null を返してきます。

c

1 /* 文字列の検索処理 */ 2 for(int i=0; i<WNUM; i++) { 3 for(char *p=words[i]; (p=strstr(p,search)); ) { 4 printf("%d 番目の文字列の%td文字目から一致\n", i, (++p)-words[i]); 5 } 6 }

(私の環境でアドレス計算結果の表示が %d は warning になりましたので %ld %td に変えています。)

投稿2023/10/24 16:48

編集2023/10/25 01:24
jimbe

総合スコア12659

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

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

int32_t

2023/10/24 21:53

> %d は warning になりましたので %ld %td を使うべきかと思います。
henta-e

2023/10/25 02:03

ご回答ありがとうございます。上記の通り該当箇所を修正したら無事理想通りの実行結果を得られました!。また、検索、入れ替え両方の簡略化の手段も教えていただきありがとうございます。
guest

0

ベストアンサー

strcpyを使ってよいなら、もっと簡単にできますが、使わない方法です。
文字列の終端はかならず、'\0'(=0x00)で終了しなければいけません。

C

1#include <stdio.h> 2#include <string.h> 3 4#define WLEN 20 5#define WNUM 6 6 7int main() { 8 char words[WNUM][WLEN] = {"Yokosuka", "Chigasaki", "Fujisawa", 9 "Yokohama", "Hiratsuka", "Sagamihara"}; 10 int command; /* 選択処理管理用変数 */ 11 12 /* 変数宣言の追加 */ 13 char search[WLEN]; 14 int pos1, pos2, i, j, match; 15 16 while (1) { 17 printf("\n"); /* 文字列(2次元配列)の出力が見やすいように1行空白行を出力 */ 18 19 /* 文字列(2次元配列)の出力) */ 20 for (i = 0; i < WNUM; i++) { 21 printf("%d: %s\n", i, words[i]); 22 } 23 /* コマンドの入力 */ 24 printf("\n処理の入力(1: 検索 2: 入れ替え 0: 終了)> "); 25 scanf("%d", &command); 26 27 switch (command) { 28 case 1: /* 検索処理 */ 29 printf("検索文字列の入力> "); 30 /* 標準入力からの検索文字列の読み込み */ 31 scanf("%s", search); 32 /* 文字列の検索処理 */ 33 for (i = 0; i < WNUM; i++) { 34 match = 0; 35 for (j = 0; j < WLEN - strlen(search); j++) { 36 if (words[i][j] == search[0]) { 37 match = 1; 38 for (int k = 1; k < strlen(search); k++) { 39 if (words[i][j + k] != search[k]) { 40 match = 0; 41 break; 42 } 43 } 44 if (match == 1) { 45 printf("%d 番目の文字列の%d文字目から一致\n", i, j + 1); 46 } 47 } 48 } 49 } 50 break; 51 case 2: /* 入れ替え処理 */ 52 printf("一つ目の位置の入力> "); 53 /* 標準入力からの一つ目の位置の読み込み*/ 54 scanf("%d", &pos1); 55 56 printf("二つ目の位置の入力> "); 57 /* 標準入力からの二つ目の位置の読み込み */ 58 scanf("%d", &pos2); 59 /* 文字列の入れ替え処理 */ 60 char temp[WLEN]; 61 62 int len1 = strlen(words[pos1]); 63 int len2 = strlen(words[pos2]); 64 int len = (len1 < len2) ? len1 : len2; 65 //追加 66 int len_long = (len1 < len2) ? len2 : len1; 67 char ch; 68 69 for (int i = 0; i < len; i++) { 70 ch = words[pos1][i]; 71 72 words[pos1][i] = words[pos2][i]; 73 words[pos2][i] = ch; 74 } 75 76 if (len1 != len2) { 77 char *longer; 78 char *shorter; 79 80 if (len1 > len2) { 81 longer = words[pos1]; 82 shorter = words[pos2]; 83 } else { 84 longer = words[pos2]; 85 shorter = words[pos1]; 86 } 87 //修正開始 88 for (i = len; i < len_long; i++) { 89 shorter[i] = longer[i]; 90 } 91 shorter[len_long] = '\0'; 92 longer[len] = '\0'; 93 //修正終了 94 } 95 break; 96 case 0: /* 処理の終了 */ 97 printf("\n"); 98 return 0; 99 break; 100 } 101 } 102 103 return -1; 104} 105

投稿2023/10/24 13:30

tatsu99

総合スコア5451

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

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

henta-e

2023/10/25 02:02

ご回答ありがとうございます。ご指摘の通り修正した結果無事理想通りの実行結果を得られました!僭越ながらベストアンサーにさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問