4

私は C を学ぶ初心者です。では、お手柔らかにお願いします。:)

文字列の各単語を「こんにちは(入力)!」に変換する非常に単純なプログラムを作成しようとしています。文 (名前を入力することを前提としています)。また、配列を練習する必要があるため、配列を使用しています。

私の問題は、ガベージが配列のどこかに入れられ、プログラムが台無しになることです。私は問題を理解しようとしましたが、役に立ちませんでした。そのため、専門家の助けを求める時が来ました。どこで間違いを犯しましたか?

ps: それもどこかに無限ループがありますが、おそらく配列に入れられたガベージの結果です。

#include <stdio.h>
#define MAX 500 //Maximum Array size.

int main(int argc, const char * argv[])
{
    int stringArray [MAX];
    int wordArray [MAX];
    int counter = 0;
    int wordCounter = 0;

    printf("Please type in a list of names then hit ENTER:\n");  
    // Fill up the stringArray with user input.
    stringArray[counter] = getchar();
    while (stringArray[counter] != '\n') {
        stringArray[++counter] = getchar();
    }

    // Main function.
    counter = 0;
    while (stringArray[wordCounter] != '\n') {     
        // Puts first word into temporary wordArray.
        while ((stringArray[wordCounter] != ' ') && (stringArray[wordCounter] != '\n')) {
            wordArray[counter++] = stringArray[wordCounter++];
        }
        wordArray[counter] = '\0';

        //Prints out the content of wordArray.
        counter = 0;
        printf("Hi ");
        while (wordArray[counter] != '\0') {
            putchar(wordArray[counter]);
            counter++;
        }
        printf("!\n");

        //Clears temporary wordArray for new use.
        for (counter = 0; counter == MAX; counter++) {
            wordArray[counter] = '\0';
        } 
        wordCounter++;
        counter = 0; 
    }
    return 0;
}

解決しました!wordCounter をインクリメントしたときに、次の if 文を最後に追加する必要がありました。:)

    if (stringArray[wordCounter] != '\n') {
            wordCounter++;
    }
4

3 に答える 3

4

int文字列を表すために配列を使用していgetchar()ますint。ただし、文字列は配列としてより適切に表現されます。これは、C では配列であるためです。 が返すというchar事実は確かに混乱を招きます。これは、 a に収まらない特別な値 を返すことができる必要があるためです。したがって、「より大きな」型である を使用します (より多くの異なる値を表すことができます)。したがって、すべての値に適合し .getchar()intEOFcharintchar EOF

char配列では、C の文字列関数を直接使用できます。

char stringArray[MAX];

if(fgets(stringArray, sizeof stringArray, stdin) != NULL)
   printf("You entered %s", stringArray);

fscanf()文字列に行末文字が残るため、それらを削除したい場合があることに注意してください。先頭と末尾の空白を削除するインプレース関数を実装することをお勧めします。これも良い練習になります。

于 2012-11-05T10:55:28.847 に答える
3
    for (counter = 0; counter == MAX; counter++) {
        wordArray[counter] = '\0';
    } 

このループに入ることはありません。

于 2012-11-05T10:40:09.773 に答える
2

ユーザー1799795、

価値があるのは(問題を解決したので)、「配列を使用する」という制限を考慮してこれを行う方法を自由に示し、なぜそのようにするのかについて少し説明することです.. . 私は経験豊富なプログラマーですが、C の第一人者ではないことに注意してください... 私を C の雑草に完全に吹き飛ばした人たちと一緒に仕事をしたことがあります (しゃれが意図されています)。

#include <stdio.h>
#include <string.h>

#define LINE_SIZE 500
#define MAX_WORDS 50
#define WORD_SIZE 20

// Main function.
int main(int argc, const char * argv[])
{
    int counter = 0;

    // ----------------------------------
    // Read a line of input from the user (ie stdin)
    // ----------------------------------
    char line[LINE_SIZE];
    printf("Please type in a list of names then hit ENTER:\n");
    while ( fgets(line, LINE_SIZE, stdin) == NULL )
        fprintf(stderr, "You must enter something. Pretty please!");

    // A note on that LINE_SIZE parameter to the fgets function:
    // wherever possible it's a good idea to use the version of the standard
    // library function that allows you specificy the maximum length of the
    // string (or indeed any array) because that dramatically reduces the
    // incedence "string overruns", which are a major source of bugs in c
    // programmes.
    // Also note that fgets includes the end-of-line character/sequence in
    // the returned string, so you have to ensure there's room for it in the
    // destination string, and remember to handle it in your string processing.

    // -------------------------
    // split the line into words
    // -------------------------

    // the current word
    char word[WORD_SIZE];
    int wordLength = 0;

    // the list of words
    char words[MAX_WORDS][WORD_SIZE]; // an array of upto 50 words of
                                      // upto 20 characters each
    int wordCount = 0;                // the number of words in the array.


    // The below loop syntax is a bit cyptic.
    // The "char *c=line;" initialises the char-pointer "c" to the start of "line".
    // The " *c;" is ultra-shorthand for: "is the-char-at-c not equal to zero".
    //   All strings in c end with a "null terminator" character, which has the
    //   integer value of zero, and is commonly expressed as '\0', 0, or NULL
    //   (a #defined macro). In the C language any integer may be evaluated as a
    //   boolean (true|false) expression, where 0 is false, and (pretty obviously)
    //   everything-else is true. So: If the character at the address-c is not
    //   zero (the null terminator) then go-round the loop again. Capiche?
    // The "++c" moves the char-pointer to the next character in the line. I use
    // the pre-increment "++c" in preference to the more common post-increment
    // "c++" because it's a smidge more efficient.
    //
    // Note that this syntax is commonly used by "low level programmers" to loop
    // through strings. There is an alternative which is less cryptic and is
    // therefore preferred by most programmers, even though it's not quite as
    // efficient. In this case the loop would be:
    //    int lineLength = strlen(line);
    //    for ( int i=0; i<lineLength; ++i)
    // and then to get the current character
    //        char ch = line[i];
    // We get the length of the line once, because the strlen function has to
    // loop through the characters in the array looking for the null-terminator
    // character at its end (guess what it's implementation looks like ;-)...
    // which is inherently an "expensive" operation (totally dependant on the
    // length of the string) so we atleast avoid repeating this operation.
    //
    // I know I might sound like I'm banging on about not-very-much but once you
    // start dealing with "real word" magnitude datasets then such habits,
    // formed early on, pay huge dividends in the ability to write performant
    // code the first time round. Premature optimisation is evil, but my code
    // doesn't hardly ever NEED optimising, because it was "fairly efficient"
    // to start with. Yeah?

    for ( char *c=line; *c; ++c ) {    // foreach char in line.

        char ch = *c;  // "ch" is the character value-at the-char-pointer "c".

        if ( ch==' '               // if this char is a space,
          || ch=='\n'              // or we've reached the EOL char
        ) {
            // 1. add the word to the end of the words list.
            //    note that we copy only wordLength characters, instead of
            //    relying on a null-terminator (which doesn't exist), as we
            //    would do if we called the more usual strcpy function instead.
            strncpy(words[wordCount++], word, wordLength);
            // 2. and "clear" the word buffer.
            wordLength=0;
        } else if (wordLength==WORD_SIZE-1) { // this word is too long
            // so split this word into two words.
            strncpy(words[wordCount++], word, wordLength);
            wordLength=0;
            word[wordLength++] = ch;
        } else {
            // otherwise: append this character to the end of the word.
            word[wordLength++] = ch;
        }
    }

    // -------------------------
    // print out the words
    // -------------------------

    for ( int w=0; w<wordCount; ++w ) {
        printf("Hi %s!\n", words[w]);
    }
    return 0;
}

現実の世界では、単語の最大長や単語数についてそのような制限的な仮定を行うことはできません。そのような制限が与えられた場合、それらはほとんど常に恣意的であり、したがってすぐに間違っていることが証明されます...この問題をすぐに解決するには、「単語」配列の代わりにリンクリストを使用する傾向があります...「動的データ構造」に到達するまで待ちます...あなたはそれらを気に入るはずです;-)

乾杯。キース。

PS: 順調に進んでいます...私のアドバイスは、「トラックインを続けてください」です...これは、練習することで非常に簡単になります。

于 2012-11-05T14:13:54.637 に答える