0

C で文字列を逆にしようとしています。reverse 関数は、(for ループ内の) 特定の場所にある文字を一時オブジェクトに割り当てるだけです。プログラム内に論理エラーは見られず、プログラムは次のコマンドを使用して gcc 4.7.2 で正常にコンパイルされます。

gcc -Wall -std=c99 reverse.c

問題を再現するには:

1.) プログラムを実行し、シェルに文字列を入力します

2.) 入力が完了したら、enter/and または EOF シグナルを押します。

問題は、元の文字列も逆文字列も印刷されないことです。これは、K&R 第 2 版の演習でもあります。この演習を完了している場合は、私のソリューションとは別のソリューションを提供していただければ幸いです。

このバグは null 文字がないことが原因だと思います。有名な printf では、入力を cin に出力するために null で終了する文字列が必要です。getline 関数は、null 文字を配列の最後に割り当てます。確実に null 文字は文字列の最初の文字になり、printf が終了します (したがって、文字/リテラル​​は出力されません)。

#include <stdio.h>

#define MAXLINE 1000

int geline(char s[], int lim);
void reverse(char line[],  int length);

int main() 
{
    char s[MAXLINE];
    char t[MAXLINE];
    int k, len;

    while ((len = getline(s, MAXLINE)) > 0) {
        if (len > 1) 
            reverse(s, len);
    }
    printf("%s", s);
    return 0;
}

void reverse (char input[], int length) 
{
    char temp[MAXLINE];
    int j = length;
    for (int i = 0; i < length; ++i, --j) {

            temp[i] = input[i];
            input[i] = input[j];
            input[j] = temp;
    }

}



int getline(char s[], int lim)
{
    int c, i;

    for (i=0; (c=getchar()) != EOF && c!='\n'; ++i) 
        s[i] = c;
    if (c== '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}
4

6 に答える 6

2

次の 2 つの論理エラーがあります。

  • int j = length;する必要がありますint j = length - 1;
  • temp[i] = input[i] ... input[j] = temp;

最後のエラーには 2 つのアプローチがあります。

  • temp単一の文字として定義:char temp; ... temp = input[i]; input[i] = input[j]; input[j] = temp;
  • で正しいインデックスを使用しますtemptemp[i] = input[i]; input[i] = input[j]; input[j] = temp[i]

このコードを試してください:

#include <stdio.h>
#define MAXLINE 1000

int geline(char s[], int lim);
void reverse(char line[],  int length);

int main () {
    char s[MAXLINE];
    char t[MAXLINE];
    int k, len;

    while ((len = getline(s, MAXLINE)) > 0) {
        if (len > 1) 
            reverse(s, len);
    }

    printf("%s", s);
    return 0;
}

void reverse (char input[], int length) {
    char temp;
    int j = length - 1;

    for (int i = 0; i < j; ++i, --j) {
            temp = input[i];
            input[i] = input[j];
            input[j] = temp;
    }
}

int getline (char s[], int lim) {
    int c, i;

    for (i=0; (c=getchar()) != EOF && c!='\n'; ++i) 
        s[i] = c;

    if (c== '\n') {
        s[i] = c;
        ++i;
    }

    s[i] = '\0';

    return i;
}
于 2013-07-01T17:32:35.070 に答える
1

(私は、の使用を許可するために-Wall -std=c99 -O3 -g、を使用してコンパイルを行いました)-ggdb

以下、気になった点とその対処法です。私はあなたが始めたスタイルにかなり近づけようとしました (たとえば、プロトタイプの配列宣言をポインターに変換したでしょうが、それは必須ではありません)。

getlineプロトタイプに がありませんでしたt

int getline(char s[], int lim);

では、実際には,mainは必要ありません。おそらくループ内にあるはずなので、各単語が逆になっていることがわかります。以下は、改行と EOF で終了する行の両方を同じもの (改行なし) に変換するため、をピックアップすることに注意してください。kt[MAXLINE]printfprintf\ngetline

int main() 
{
    char s[MAXLINE];
    int len;

    while ((len = getline(s, MAXLINE)) > 0) {
        if (len > 0) 
            reverse(s, len);
        printf("%s\n", s);
    }
    return 0;
}

上の例でもgetline(s, MAXLINE)getline(s, sizeof(s) / sizeof(*s) - 1)フェンスポスト エラーに注意してください ( に注意してください- 1)。

このreverse関数は、変数を持つことをスキップするために xor の狂気に陥ることなく、大幅に改善できます (ただし、Daffra の例は、特に途中で正しく停止するという点で興味深いものです)。代わりに、中間点までインデックスを付けるだけの感覚を持つことは、明らかに勝利です. tempそれと一時的な文字に配列を縮小するまでの間に、一般的なスタイルが保持されます。

void reverse (char input[], int length) 
{
    int max = length - 1;  /* keep the final NUL in place */
    for (int i = 0; i <= max / 2; ++i) {
        char ch = input[i];
        input[i] = input[max - i];
        input[max - i] = ch;
    }
}

上記gcc -O3では、コードに重大な修正を加えることができるため、すべてのループ テストなどで長い除算が実行されることを心配する本当の理由はありません。たとえば、それ自体が自動的に最適化されるgdbという報告がiあり、これは非常に興味深いことです。最初に適切で読みやすいコードを作成し、コンパイラを信頼して、後で最適化します。

最後に、 (CRITICAL!)getlineに対するテストlimと、改行を NUL に変換する利点があります。

int getline(char s[], int lim)
{
    int i, c;

    for (i=0; (i <= lim) && ((c=getchar()) != EOF) && (c != '\n'); ++i) 
        s[i] = c;
    s[i] = '\0';

    return i;   /* return the index to the final NUL, same as length w/o it */  
}

一時的に 10 に設定MAXLINEすると、このバージョンが非常に長い行をかなり適切に処理し、文字を失うことなく 2 つの別々の行に分割することが示されます。

文字列を長さで記述するか、末尾の NUL へのインデックスで記述するかを明確に決定するように注意してください。これは、ループ、制限、変数名などの言い回しに影響し、明らかにそれらを混同することは、フェンスポスト エラーの典型的な原因です。

お役に立てれば。

于 2013-07-05T06:47:24.007 に答える
1
 int j = length - 1; // Thanks to @chux
 for (int i = 0; i < j; ++i, --j) { // or <= length / 2
        char temp = input[i];
        input[i] = input[j];
        input[j] = temp;

temp は不要であり、完全に正しく使用されているわけではありません。

値を 2 回スワップしているため、サイクルの後半でスワップが復元されます。:)


プロトタイプに 't' ( geline) がありません。したがって、多分

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

取られる?

于 2013-07-01T17:18:09.627 に答える