こんにちは
C言語を始めたばかりのものです。
下のプログラムは最大100人で(実際は101人)まで少ない人数で5人か10人くらい抽選で選ぶプログラムの製作途中の段階です。
Visual C++2010で作っています。
とりあえずinfor関数を使ってscanfで入力した文字で配列の中身を表示しようとするプログラムを作っていますが、コンパイルして適当な文字を入力してEnterを押したところ
抽選.exe の 0x53a813af (msvcr100d.dll) でハンドルされていない例外が発生しました: 0xC0000005: 場所 0x00000073 を読み込み中にアクセス違反が発生しました。
と出て出来ません。もしかしたら初歩的な間違いかも知れませんが回答お願いします。
#include<stdio.h>
void infor(char name[]){
int j=0;
for(j=0;j<=100;j++){
printf("%s ,",name[j]);
}
}
int main(void){
int count,i;
char name[100];
count=1;
i=0;
while(i<=100){
printf("%d人目:",count);
scanf("%s",&name);
infor(name);
i++;
}
return 0;
}
C言語プログラムの製作
Re: C言語プログラムの製作
コードを提示するときはBBcodeを有効にした状態でcodeタグで囲み、
かつ適切なインデントをしていただけると、見やすくて助かります。
かつ適切なインデントをしていただけると、見やすくて助かります。
#include<stdio.h>
/* どれくらいのテキストが入力されるかわからないので、バッファを多めに取っておく */
#define BUFFER_MAX 100000
void infor(char name[][BUFFER_MAX]){ /* main関数のname変数の型に合わせて修正 */
int j=0;
for(j=0;j<=100;j++){
/* 元のコードではここでアドレスとして不正な値が渡されるので、アクセス違反になる */
printf("%s ,",name[j]);
}
}
int main(void){
int count,i;
/* 101人分のデータを読み込むなら、要素は101個確保しないと領域外アクセスを起こす */
/* 大きい配列はstaticまたはグローバル変数(またはmallocなどで動的確保)にしないと、
* スタックオーバーフローを起こす可能性が高くなる */
static char name[101][BUFFER_MAX];
count=1;
i=0;
while(i<=100){
printf("%d人目:",count);
scanf("%s",name[i]); /* %sは文字列を読み込む領域の先頭を指すchar *型データを要求する */
infor(name);
i++;
count++; /* せっかくcount変数があるのに、更新しないのは不自然(致命的ではない) */
}
return 0;
}
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: C言語プログラムの製作
ありがとうございます。
おかげで情報が表示出来、制作を進めてみたところあともうちょっとなんですが、抽選を行うと重複して結果が出てしまうことがあり、重複を出さないようにするためにはどうしたらよいですか?
おかげで情報が表示出来、制作を進めてみたところあともうちょっとなんですが、抽選を行うと重複して結果が出てしまうことがあり、重複を出さないようにするためにはどうしたらよいですか?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_MAX 10000000
void infor(char name[][BUFFER_MAX]){//名簿の中身を表示
int j;
for(j=0;j<=99;j++){
printf("%s,",name[j]);
}
printf("\n");
}
void sel(char name[][BUFFER_MAX],int sele){//抽選するための関数
int a,k;
int selectbox[50];
for(a=0;a<50;a++){
if(strcmp(name[a],"")==0){//nameで配列データがなくなるまでaをカウント
a=a-1;//aのままではデータがない配列まで差しているので引いておく
break;
}
}
puts("結果");
for(k=0;k<sele;k++){//抽選を行う。ここが間違いだと思うが、重複して出てしまうことがあり、重複を出さない方法がわからない
selectbox[k]=rand()%a;
printf("%s\n",name[selectbox[k]]);
}
}
int main(void){
int count;//登録するごとに人数をカウント
int i;//名簿の配列リストのカウント
char select[10];//gets関数を使って数字以外の文字を入力したときにエラーを出すための文字列変数
int sele;//select変数で数字が入力されたときに格納
static char name[100][BUFFER_MAX];//名簿:配列ごとに名前の登録
count=1;
i=0;
while(1){
printf("何人抽選しますか?:");
gets(select);
sele=atoi(select);//atoi関数でchar型からint型に変換
if (1 <= sele && sele <= 50)
break;
else
printf("抽選人数は1~50人でお願いします。\n");//1~50以外の数字、文字を入力したときにエラー
}
puts("抽選希望の登録を始めます。");
puts("抽選を開始するなら「抽選」と入力してください");
while(i<=99){
printf("%d人目:",count);
scanf("%s",name[i]);
if(strcmp(name[i],"抽選")==0&&i-1<sele){//抽選人数<抽選希望人数にするためにエラーを出す
printf("抽選希望人数は%d人以上でなくてはいけません。\n",sele+1);
continue;
}
if(strcmp(name[i],"抽選")==0){//抽選人数<抽選希望人数のときにsel関数で抽選開始
sel(name,sele);
continue;
}
if(i==99){//登録した人数が100人に達したとき
puts("これ以上登録できません。抽選を開始します。");
sel(name,sele);
continue;
}
infor(name);//人を登録していくと毎にname配列の状態を確認
i++;
count++;
}
return 0;
}
Re: C言語プログラムの製作
とりあえず以下の方法を思いつきました。
案1.抽選のたびに重複をチェックして、重複していれば再度抽選する
案2.selectbox[0]=0,selectbox[1]=1,...selectbox[a]=a を用意してランダムに何回か並べ替えた後、selectbox[0]~selectbox[sele-1]までを当選、とする
「puts("結果");」の後を以下のように変更します。
案1
案2
こんな感じかなと。
他にも方法はあるとは思いますが(当選した人をname配列から除外するとか)、案ということで。
なお、rand()%a の結果は 0~(a-1)なので、元のプログラムだと最後の人が当選しないかなと思いました。
今回の回答ではその辺を考慮しませんでしたが、ご確認いただければと思います。
案1.抽選のたびに重複をチェックして、重複していれば再度抽選する
案2.selectbox[0]=0,selectbox[1]=1,...selectbox[a]=a を用意してランダムに何回か並べ替えた後、selectbox[0]~selectbox[sele-1]までを当選、とする
「puts("結果");」の後を以下のように変更します。
案1
for(k=0;k<sele;k++){
selectbox[k]=rand()%a;
for(int l=0;l<k;l++) {
// 重複が見つかったら一つ戻ってもう一度抽選
if(selectbox[k]==selectbox[l]) {
k--;
continue;
}
}
printf("%s\n",name[selectbox[k]]);
}
for(k=0;k<=a;k++){ // selectbox[0]=0,selectbox[1]=1,...selectbox[a]=a を用意
selectbox[k]=k;
}
for(k=0;k<99;k++) { // 何回かランダムに並べ替え
int i,j,tmp;
i=rand()%a;
j=rand()%a;
tmp=selectbox[i];
selectbox[i]=selectbox[j];
selectbox[j]=tmp;
}
for(k=0;k<sele;k++){ // selectbox[0]~selectbox[sele-1]までを当選
printf("%s\n",name[selectbox[k]]);
}
他にも方法はあるとは思いますが(当選した人をname配列から除外するとか)、案ということで。
なお、rand()%a の結果は 0~(a-1)なので、元のプログラムだと最後の人が当選しないかなと思いました。
今回の回答ではその辺を考慮しませんでしたが、ご確認いただければと思います。