2016-11-11 14 views
0

私は10人のレーサーから情報を取得するプログラムを作成しようとしています。プログラムは、名、姓、年齢、性別(m/f)、レースの時間(hh:mm:ss)を取得して保存します。これを行うために、私は各レーサーのための上記の要素のそれぞれを含む構造の配列を持つことを計画しました。 「最初のレーサーの名前を入力してください」という質問は、「最初の」という単語を「2番目の」、「3番目の」などに変更する必要があるためです。ループはそれを行う。だから私は、配列の最初の要素が "first"というような文字列を作ることにしました。それで、私はplace配列の各要素にアクセスすることによって、各レーサーの正しい単語を印刷するループを使用することができました。文字列の配列とそれらの要素の印刷

私は文字列や文字列の配列に慣れていないので、私はオンラインでいくつかのヘルプを検索し、次のプログラムを思いつきました。ポインタを持つ文字配列を使用しています。文字列とは何かとにかく、私はプログラムを実行するときに深刻な問題が発生し、Visual Studioを再起動する必要があります。誰かが私に手を差し伸べて、これらの文字列の配列とポインタの意味についてのいくつかの謎を解明するのに役立ちます。ありがとう!

#include <stdio.h> 
#include <math.h> 

typedef struct DATASET 
{ 
    char firstname[12], lastname[12], gender; 
    int age, hours, minutes, seconds; 
}; 

#define MaxRacers 10 

int main() 
{ 
    int i; 
    DATASET data[MaxRacers]; 

    char *places[MaxRacers]; 

    char place1[6] = "First"; 
    char place2[7] = "Second"; 
    char place3[6] = "Third"; 
    char place4[7] = "Fourth"; 
    char place5[6] = "Fifth"; 
    char place6[6] = "Sixth"; 
    char place7[8] = "Seventh"; 
    char place8[7] = "Eighth"; 
    char place9[6] = "Ninth"; 
    char place10[6] = "Tenth"; 

    places[0] = place1; 
    places[1] = place2; 
    places[2] = place3; 
    places[3] = place4; 
    places[4] - place5; 
    places[5] = place6; 
    places[6] = place7; 
    places[7] = place8; 
    places[8] = place9; 
    places[9] = place10; 


    printf("%s", places[1]); // TEST which works fine 

    for(i = 0, i < MaxRacers; i = i + 1;) 
    { 
     printf("Enter the name of the %s finisher\n", places[i]); // Problem 
    } 



    getchar(); 
    return(0); 


} 

今、アイブ氏は、イムは、今のようにすぐに私は最初のフィニッシャープログラムは、コマンドウィンドウの外に出て、新しいウィンドウが立ち上がるの最後の名前の入力が完了して問題に実行して、さらに少し行く事を得ました言って:

「ConsoleApplication30.exeで0x0FF6D0F1(ucrtbased.dll)でスローされる例外:0xc0000005で:。。アクセス違反の書き込み場所0xFFFFFFCC

この例外のハンドラがある場合、プログラムは安全に継続することができる

#include <stdio.h> 
#include <math.h> 

struct DATASET 
{ 
    char firstname[12], lastname[12], gender; 
    int age, hours, minutes, seconds; 
}; 

#define MaxRacers 10 

int main() 
{ 
    int i; 
    DATASET data[MaxRacers]; 

    char *places[] = { "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", "Ninth", "Tenth" }; 


    for (i = 0; i < MaxRacers; i++) 
    { 
     printf("Enter the first name of the %s finisher:\n", places[i]); 
     scanf("%s", data[i].firstname); 
     printf("Enter the last name of the %s finisher:\n", places[i]); 
     scanf("%s", data[i].lastname); 
     printf("Enter the gender of the %s finisher: [m/f]: \n", places[i]); 
     scanf("%c", data[i].gender); 
     printf("Enter the age of the %s finisher:\n", places[i]); 
     scanf("%d", data[i].age); 
     printf("Enter the time of the %s finisher: [hh:mm:ss]\n", places[i]); 
     scanf("%d:%d:%d", data[i].hours, data[i].minutes, data[i].seconds); 
     printf("\n\n"); 
    } 




    getchar(); 
    return(0); 


} 
+0

'places [4] - place5;はtypoです。コンパイラはそれについてあなたに警告していたでしょう。 – Evert

+0

'char * place1 =" First "を使う方がおそらくもっと標準です。 – Evert

+1

または、すべての行を割り当てます。 'char * places [] = {"最初 "、" 2番目 "、" 3番目 "、...};'。それははるかに明確になるでしょう。 – Evert

答えて

1
for(i = 0, i < MaxRacers; i = i + 1;) 

forループはそのように動作しません。このお試しください:また

for(i = 0; i < MaxRacers; i++) 
//  ^    ^
//  |     | 
//  semicolon here  more idiomatic 

を、あなたは、慣用的な文字配列の初期化を使用する必要があります。

char *places[MaxRacers] = { "First", "Second", ... }; 

だけでなく、それはplacesのあなたの20行以上のタイプへの道が容易であるため、だけでなく、そこにあるので、我々はそれに取り組んでいる一方で、

places[3] = place4; 
places[4] - place5; // <---- whoops 
places[5] = place6; 

のようなタイプミスを逃さはるかに少ないチャンス

はほとんど意味がありません。 typedef名は作成されないので、typedefという単語は役に立たない。そのことを、この宣言

DATASET data[MaxRacers]; 

は、それはおそらくあなたがC++コンパイラを使用している意味C++、に有効であるC.に無効あるのでそれは

struct DATASET 
{ // whatever 
}; 

に相当します。 C言語を学んでいる場合は、ソースファイルの拡張子が.cであることを確認してください。この質問のあなたの2回目の反復で

+0

私はC++を使っていると思います。私のソースはsource.cppです。私はあなたの提案を編集しましたが、それはまだ動作していません。 – Dwhaley

+0

forループの構文を修正しても構いませんが、ヘッダーファイルのデバッガに狂っていて、フリーズします – Dwhaley

+0

更新された答えを見てください。 –

1

、あなたがいることを報告:

Imは、すぐに私は、私は信じている最初のフィニッシャー

の最後の名前の入力が完了して、今問題に実行していますこの問題は、data[]と間違って宣言したことが原因です。 DATASETstruct、ないtypedefので、次のものが必要です。

struct DATASET data[MaxRacers]; 

しかし、これは新しい問題を明らかにする。 scanf()へのお電話にはいくつかの問題があります。まず、のアドレスに、scanf()の結果をいくつかのインスタンスで保存することに失敗しています。これを修正するには、次のように変更する必要があります。

printf("Enter the gender of the %s finisher: [m/f]: \n", places[i]); 
scanf("%c", &data[i].gender); 
printf("Enter the age of the %s finisher:\n", places[i]); 
scanf("%d", &data[i].age); 
printf("Enter the time of the %s finisher: [hh:mm:ss]\n", places[i]); 
scanf("%d:%d:%d", &data[i].hours, &data[i].minutes, &data[i].seconds); 

さらに別の問題が明らかになりました。 (悪)関数scanf()は改行やその他の文字を後に残し、次の入力関数の入力ストリームを汚染します。 I personally usually write a function to handle user input in the form of stringsを入力し、数値入力が必要な場合はstrtol()を使用して結果を変換します。そして、このようなあなたの入力コードを変更

void clear_stream(void) 
{ 
    int ch; 

    while ((ch = getchar()) != '\n' && ch != EOF) 
     continue;     // remove unwanted characters 
} 

:あなたがするため

最も簡単な方法は、しかし、単に%c指定子でscanf()を使用する前に、入力ストリームをクリアするために関数を記述することです

printf("Enter the first name of the %s finisher:\n", places[i]); 
scanf("%s", data[i].firstname); 
printf("Enter the last name of the %s finisher:\n", places[i]); 
scanf("%s", data[i].lastname); 
printf("Enter the gender of the %s finisher: [m/f]: \n", places[i]); 
clear_stream(); 
scanf("%c", &data[i].gender); 
printf("Enter the age of the %s finisher:\n", places[i]); 
scanf("%d", &data[i].age); 
printf("Enter the time of the %s finisher: [hh:mm:ss]\n", places[i]); 
scanf("%d:%d:%d", &data[i].hours, &data[i].minutes, &data[i].seconds); 
printf("\n\n"); 

多くの書式指定子では、scanf()は、改行を含む先頭の空白をスキップします。しかし、これは%c指定子には当てはまりません。つまり、文字列を入力すると、入力ストリームに残っている改行が、必要な文字の代わりに選択されます。

これらの変更により、コードが実行されます。しかし、あなたの入力スキームは壊れやすいです。入力があったことを確認するためにチェックされず(scanf()は読み取られた値の数を返します)、値を検証しません。ユーザーに年齢を入力させますか?あなたの入力コードが正しいかどうかを確かめるためには、少なくとも入力コードを再考してほしい。 scanf()はエラーが起こりやすいので、実際にはfgets()の使用を検討するか、以前にリンクしたような独自の入力関数を記述する必要があります。

関連する問題