あなたは近くにいます。これがあなたのコードの作業バージョンです。scanf()
は ... の番号から改行を残すことに注意してください。二度とfgets()
使用しないからですgets()
よね?...そのため、.の後の改行まで読む必要がありますscanf()
。もちろん、「コンピューターに数えさせるよりも、人間が数えた方が良いと人々が考えるのはなぜですか?」という興味深い質問があります。カウントを気にしない方が賢明でしょう。改訂されたコードn
は、50 を超えないことを確認するために検証されることに注意してください。
長さ 9 以下の行で動作する改訂されたコード
#include <assert.h>
#include <stdio.h>
#include <string.h>
void sort(char s[50][10], int);
int main(void)
{
int i;
int n = 0;
char s[50][10];
char line[11];
if (scanf("%d", &n) != 1)
{
fprintf(stderr, "Failed to read a number\n");
return 1;
}
if (n <= 0 || n > 50)
{
fprintf(stderr, "%d is out of the range 1..50\n", n);
return 1;
}
// Gobble rest of first line
while ((i = getchar()) != EOF && i != '\n')
;
for (i = 0; i < n; i++)
{
if (fgets(line, sizeof(line), stdin) == 0)
break;
// Remove newline from input
size_t len = strlen(line);
assert(len > 0 && len <= sizeof(s[i]));
line[len-1] = '\0';
strcpy(s[i], line);
}
n = i; // In case the file was shorter than stated!
printf("Before:\n");
for (i = 0; i < n; i++)
printf("%s\n", s[i]);
sort(s, n);
printf("After:\n");
for (i = 0; i < n; i++)
printf("%s\n", s[i]);
return 0;
}
void sort(char s[50][10], int n)
{
int i, j, cmp;
char tmp[10];
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++)
{
for (j = 0; j < n-1; j++)
{
cmp = strcmp(s[j], s[j+1]);
if (cmp > 0)
{
strcpy(tmp, s[j+1]);
strcpy(s[j+1], s[j]);
strcpy(s[j], tmp);
}
}
}
}
このコードは、最大 9 個のデータ文字、改行、および終端の null を受け入れるのに十分な長さの文字列に行を読み取ります。改行を削除し、最大 9 つのデータ文字と終端の null を残します。
サンプルラン:
Before:
Number 34
Number 39
Number 32
Number 30
Number 22
Number 34
Number 57
Number 28
Number 30
Number 47
Number 43
Number 23
Number 22
After:
Number 22
Number 22
Number 23
Number 28
Number 30
Number 30
Number 32
Number 34
Number 34
Number 39
Number 43
Number 47
Number 57
長さ 8 以下の行で動作するオリジナル コード
#include <assert.h>
#include <stdio.h>
#include <string.h>
void sort(char s[50][10], int);
int main(void)
{
int i;
int n = 0;
char s[50][10];
if (scanf("%d", &n) != 1)
{
fprintf(stderr, "Failed to read a number\n");
return 1;
}
if (n <= 0 || n > 50)
{
fprintf(stderr, "%d is out of the range 1..50\n", n);
return 1;
}
// Gobble rest of first line
while ((i = getchar()) != EOF && i != '\n')
;
for (i = 0; i < n; i++)
{
if (fgets(s[i], sizeof(s[i]), stdin) == 0)
break;
// Remove newline from input
size_t len = strlen(s[i]);
assert(len > 0);
s[i][len-1] = '\0';
}
n = i; // In case the file was shorter than stated!
printf("Before:\n");
for (i = 0; i < n; i++)
printf("%s\n", s[i]);
sort(s, n);
printf("After:\n");
for (i = 0; i < n; i++)
printf("%s\n", s[i]);
return 0;
}
void sort(char s[50][10], int n)
{
int i, j, cmp;
char tmp[10];
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++)
{
for (j = 0; j < n-1; j++)
{
cmp = strcmp(s[j], s[j+1]);
if (cmp > 0)
{
strcpy(tmp, s[j+1]);
strcpy(s[j+1], s[j]);
strcpy(s[j], tmp);
}
}
}
}
「大きな」変更点は、関数配列パラメーターが宣言および定義される方法です。1 行あたり 10 文字の 50 行の配列を渡すので、関数でそれを指定するだけです。プログラムの動作を変更せずに、関数パラメーターの次元から 50 を削除できます。
サンプル入力:
8
fed
abc
cba
def
hij
cba
xyz
aaa
実行例:
$ ./srt < data
Before:
fed
abc
cba
def
hij
cba
xyz
aaa
After:
aaa
abc
cba
cba
def
fed
hij
xyz
$
これを修正する必要があったという事実は、制限をテストすること (および制限を慎重に定義すること) の重要性を示しています。
改訂されたコードはまだ汎用コードではありません。入力の最大 50 行の固定制限、入力の一部として必要な行数のカウント、および行あたり最大 10 文字の固定行長はすべて、おもちゃのコードになります。そのため、GIGO(ガベージ イン、ガベージ アウト)は理不尽な反応ではありません。データ ファイルに長すぎる行が含まれている場合は、得られるものを取得します。コードがクラッシュすることはありませんが、出力が意味をなさない場合があります。