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

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

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

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

Q&A

解決済

3回答

7985閲覧

C言語 関数 文字列の反転について

Takumi0106

総合スコア17

C

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

0グッド

0クリップ

投稿2015/10/03 02:35

現在C言語の関数を学んでいる学生です。
ユーザーが入力した文字列の初めから4文字を反転して返す関数を作ろうと下のコードを書きました。

#include <stdio.h> void hanten(); int main(void) { char s[80]; gets(s); hanten(s); return 0; } void hanten() { int i, k; char s[80]; k = 0; while (1) { if (s[k] == '\0')break; k++; } for (i = (k >= 3 ? 3 : k); i >= 0; i--) { printf("%c", s[i]); } }

実行したところ

abcdef
フフフフ続行するには何かキーを押してください . . .

といった具合に、どんな文字列を入力しても
フフフフとコンピュータに笑われてしまうのですが、これは何が原因なのでしょうか?
初歩的な質問だと思うのですが、解説頂けると嬉しいです。

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

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

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

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

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

guest

回答3

0

main関数の中のsとhanten関数のなかのsはそれぞれ独立しており、別物だからです。hanten関数でのsには入力された文字列が入っているわけでは無く、char s[80];で初期化されたときの文字列(何が入るかはコンパイラや環境によって異なります。今回は毎回"フフフフ"から始まる文字列だったというわけです。)が入っています。単純にそれが出力されただけです。

詳細な解説など

修正してみたコードを下記に示します。
http://ideone.com/f08zmt
このコードで修正した問題点をあげます。

  1. マジックナンバー(80の部分)を使用すべきではない。

char配列のサイズを80と直接書いていますが、この書き方はマジックナンバーと言われ、どのようなプログラミング言語であっても推奨されません。マクロを使って定義することを推奨します。

C

1#define BUFF_SIZE 80 2... 3 char s[BUFF_SIZE];
  1. 関数宣言や定義で引数部分を省略(())を使用すべきではない。

C言語において、関数宣言・定義における仮引数部分が無い、つまり()と書くことは、「引数は何でもいい」といいという意味です。これはどのような引数をつけて関数を呼び出してもコンパイルエラーにはなりません。また、別のところで仮引数を定義しないと、その引数を使うこともできません。文字列を渡したいのなら、きちんと宣言・定義両方に書くべきです。逆に、引数を何も渡さないとするなら、(void)と明記してください。

C

1void hanten(char *s); 2... 3void hanten(char *s) { 4 // sは仮引数として使うため、char s[80];をいれてはいけません。 5 ... 6}
  1. gets使用してはいけない

C言語のgetsはセキュリティ上の問題があるため使用してはいけません。代わりにfgets等を使用してください。また、getsは最新のC言語仕様(C11)では廃止されています。
参照: Wikipedia: gets

C

1 fgets(s, BUFF_SIZE, stdin);
  1. 文字列の長さを知りたいならstrlenを使おう。

while部分でどこまで文字列があるかを確認しているようですが、標準関数に文字列の長さを調べるstrlenがあります。車輪の再開発はせずに、なるべく標準関数を使いましょう。

C

1#include <string.h> 2... 3 k = strlen(s); 4 for (i = (k >= 4 ? 3 : k - 1); i >= 0; i--) { 5 ...

kには長さが入りますので、k - 1が最後の文字になることだけ注意してください。

投稿2015/10/03 03:23

raccy

総合スコア21735

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

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

Takumi0106

2015/10/03 16:29

遅くなりましたが、わかりやすくまた、深い説明ほんとうにありがとうございます。 C言語の入門書を順にこなしているだけではわからないことが多くあることに気づかされました。以後、励みます。
guest

0

まず,gets関数を使われていますが,これはバグを引き起こしやすく,現在の新しい規格では削除されているはずです.私の実行環境でも
”warning: this program uses gets(), which is unsafe.”と怒られてしまいます.(下のリンクにも例としてgets関数が紹介されています.)
なのでscanfを使いましょう.
次に,hanten関数ですが,引数を指定するのを忘れてしまっています!hanten関数の中でchar s[80]とまた定義されていますが,これも消しましょう.
ので以下のようにすると良いでしょう.

C

1#include <stdio.h> 2 3void hanten(char[]); 4 5int main(void) { 6 char s[80]; 7 scanf("%s", s); 8 hanten(s); 9 return 0; 10} 11void hanten(char s[]) { 12 int i, k; 13 14 k = 0; 15 while (1) { 16 if (s[k] == '\0')break; 17 k++; 18 } 19 20 for (i = (k >= 3 ? 3 : k); i >= 0; i--) { 21 printf("%c", s[i]); 22 } 23 printf("\n"); 24}

バッファオーバーフロー

投稿2015/10/03 03:03

H_I_D

総合スコア20

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

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

Takumi0106

2015/10/03 03:14

丁寧な説明、ありがとうございます。 gets関数はバグを引き起こしやすいというのは知らなかったので勉強になりました。
H_I_D

2015/10/03 03:34

すみません.ご指摘ありがとうございます.
guest

0

ベストアンサー

main関数でsを渡そうとしているのに、hanten関数の宣言に、引数がありません。

文字列を渡せるようにするには、こうします。

lang

1void hanten(char *s) { 2 int i, k; 3 /* char s[80]; */ /* これは要らない */ 4 /* 以下略 */ 5}

フフフフとなるのは、何も入っていない+未初期化の文字列sを処理しようとしているからです。
この文字は開発環境によって異なります。

これだけではまだ完成ではありませんが、残りは質問者さんがご自分でお試しになった方が良いでしょう。

投稿2015/10/03 02:59

編集2015/10/03 03:01
argius

総合スコア9390

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

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

Takumi0106

2015/10/03 03:09

指摘頂いたところを直したところ、目的の出力を得ることができ、理解を深めることができました。有難うございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問