本題に入る前に。
- 整形しよう。
せめてインデントは揃えるようにしてください。ソースコードは綺麗に整形しているだけで、読みやすさが断然違います。読みやすければ、動きもわかりやすくなり、どこに問題があるかも把握しやすくなります。ツールなどを用いても良いでしょう。
2. グローバル変数は使わずに、ローカル変数を引数で渡そう。
グローバル変数は悪です。どうしても使用しなければ実現できない場合を除き、使用すべきではありません。変数は基本的にローカル変数を使いましょう。関数間で使用する変数は引数として渡しましょう。
3. 変数の複数宣言は使わないようにしよう。
int *a, b = 0;
と言った変数の複数宣言は混乱の元になりやすく、使用すべきではありません。一つの宣言で一つ変数だけを宣言するようにしてください。
4. マジックナンバーはマクロ定数で定義しよう。
char str[256];
としたときの256
部分はマジックナンバーと言われます。このマジックナンバーがソースコードの複数箇所に現れると、問題が起きるときがあります。それは、数を変えたときです。全部変更したつもりが変更し忘れがあったりすると、バッファオーバーフローなどの致命的な問題を引き起こします。マクロ定数にして、一括で変更できるようにしましょう。
5. printf()
が'\n'で終わらないときは、flushしよう。
C言語の入出力ではバッファリングというものを行っています。ある程度バッファにため込むことで、低速な入出力をなるべく停止しないように行うという仕組みです。printf()
も直接標準出力に書き込むのではなく、標準出力のバッファに書き込むに過ぎません。そして、C言語の標準出力のバッファでは、バッファが一杯になるか、改行'\n'が現るまで、出力をしないようになっています。つまり、prinf()
が'\n'で終わってなければ、最後まですぐに出力しない場合があります。そういうときはfflush()
を使用して、バッファ内容を強制的に出力するように必要があります。
6. scanf()
で'%s'のみは危険なので、大きさを指定するか、scanf_s()
やfegts()
を使おう。
scanf("%s", str)
とした場合gets()
と同じぐらいの危険性をはらんでいます。絶対にこのままにすべきではありません。scanf("%9s", str)
やscanf_s("%s", str, 10)
等とするか、またはfgets()
を使いましょう。
7. scanf()
等を使用したときは、戻り値チェックとバッファ空読みをしよう。
標準入力が閉じられるなどの理由でscanf()
等が失敗するときがあります。必ず戻り値チェックをして、それ以上読み込みできないときは終了するようにしてください。そうでないと無限ループになり、プログラムが暴走するときがあります。また、用意した文字列の長さが足りず、改行まで読み込まれなかった場合もあります。次の読み込みでは読み込まれなかった文がバッファに残っているため、邪魔になります。空読みをして、バッファを空にしてから、次の読み込みを待ちましょう。
8. malloc()
の戻り値がNULLでないかをチェックしよう。
メモリが足りないときはmalloc()
は失敗し、NULLを返します。そのまま続行してしまうと、アプリケーションが落ちてしまいます。戻り値がNULLでないかをチェックして、失敗した場合は、エラーメッセージなどを出してから、終了するようにしましょう。
9. void hoge()
と関数宣言/定義で()内を省略するのはやめよう。
C言語ではvoid hoge()
とvoid hoge(void)
は意味が異なります。混同してはいけません。()
とするのは引数が何でも良いという意味で、古い書き方であり、引数の型チェックがされなくなるためバグの元になります。引数無しであれば、(void)
と明示しましょう。
以上を踏まえて、書き換えたら全く別物になってしまいました。ごめんなさい。
C
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#define MOJI_SIZE 256
6
7struct cell {
8 char c;
9 struct cell *next;
10};
11
12void push(struct cell **p_stack, char c);
13char pop(struct cell **p_stack);
14struct cell *make_stack(char *str);
15void free_stack(struct cell *stcak);
16void print_stack(struct cell *stack);
17
18int main(void)
19{
20 while (1) {
21 printf(u8"文字列かendを入力してください->");
22 fflush(stdout);
23
24 char moji[MOJI_SIZE];
25 char *result_str = fgets(moji, MOJI_SIZE, stdin);
26
27 if (result_str == NULL) {
28 break;
29 }
30
31 if (moji[strlen(moji) - 1] == '\n') {
32 moji[strlen(moji) - 1] = '\0';
33 } else {
34 printf(u8"入力文字が多すぎます。\n");
35 while (1) {
36 int c = getchar();
37 if (c == EOF || c == '\n') {
38 break;
39 }
40 }
41 continue;
42 }
43
44 if (strcmp(moji, "end") == 0) {
45 break;
46 }
47
48 struct cell *stack = make_stack(moji);
49 struct cell *reverse_stack = NULL;
50 print_stack(stack);
51 while (stack != NULL) {
52 push(&reverse_stack, pop(&stack));
53 }
54 print_stack(reverse_stack);
55 printf("\n");
56 free_stack(stack);
57 stack = NULL;
58 free_stack(reverse_stack);
59 reverse_stack = NULL;
60 }
61 return 0;
62}
63
64void push(struct cell **p_stack, char c)
65{
66 if (*p_stack == NULL) {
67 *p_stack = (struct cell *)malloc(sizeof(struct cell));
68 if (*p_stack == NULL) {
69 fprintf(stderr, u8"メモリ確保に失敗しました。");
70 exit(1);
71 }
72 (*p_stack)->c = c;
73 (*p_stack)->next = NULL;
74 return;
75 }
76 push(&((*p_stack)->next), c);
77}
78
79char pop(struct cell **p_stack)
80{
81 struct cell **p_next = &((*p_stack)->next);
82 if (*p_next == NULL) {
83 char c = (*p_stack)->c;
84 free_stack(*p_stack);
85 *p_stack = NULL;
86 return c;
87 }
88 return pop(p_next);
89}
90
91struct cell *make_stack(char *str)
92{
93 struct cell *stack = NULL;
94 for (char *p_c = str; *p_c != '\0'; p_c++) {
95 push(&stack, *p_c);
96 }
97 return stack;
98}
99
100void free_stack(struct cell *stack)
101{
102 if (stack == NULL)
103 return;
104 struct cell *next = stack->next;
105 free(stack);
106 free_stack(next);
107}
108
109void print_stack(struct cell *stack)
110{
111 if (stack == NULL) {
112 return;
113 }
114 printf("%c", stack->c);
115 print_stack(stack->next);
116}