入力処理のプログラム

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
マーチ

入力処理のプログラム

#1

投稿記事 by マーチ » 11年前

初めまして。学校の課題で文系にも関わらずC言語のプログラミングを行うことになってしまいました。
今日明日中に提出をしなくてはならず自らの限界を感じてしまい、
是非皆様のお力をお貸しいただければと思い書き込ませていただきました。

入力した文字列2つを連結して表示させるプログラムを作っています。

出来ない点は
・空白を入力、または何も入力しない場合、注意文を表示させたい。(文字数が多すぎますと同様に)
空白:スペースが入っています。
何もなし:文字を入力してください

・最後の「1か0を入力してください」で数字以外の文字を入力すると無限ループに入ってしまうのを、
「1か0を入力してください」と一行のみ表示させ、再度1か0を入力できるようにしたい。

コードを書き込ませていただきます。是非よろしくお願いいたします。

コード:

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

void input(char in[], int n)
{

 printf("%dつ目の文字を入力してください(半角20字、全角6文字以内)\n", n);
 scanf("%s", in);

 //*
 while(!strcmp(in, EOF)){
  printf("ちゃんと文字を入力してください\n");
  scanf("%s", in);
 }
 //*/

 while(strlen(in) > 20){
  printf("文字数が多すぎます.\n");
  printf("もう一度文字を入力してください.\n");
  scanf("%s", in);
 }
}

void joint(char in1[], int n1, char in2[], int n2)
{
//outの関数 文字列の格納
    char *out;
    
    int i,j,k;
    //ヒープメモリの確保
    out = (char *)malloc(sizeof(char) * (n1 + n2 + 1));

    //繰り返しで配列 1つ目の文字数終わったら
    for(i = 0; i < n1; i++)
        out[i] = in1[i];

    //空白を入れる
    out[i] = ' ';

    //2つ目の文字列の配列を入れる
    j = i+1;
    for(k = 0; k < n2; k++){
        out[j] = in2[k];
        j++;
    }

    //2つ目の文字列以降は何も入れない
    out[j] = 0;

    //outの配列を表示
    printf("%s\n", out);

    //ヒープメモリの解放
    free(out);
}

int main(void)
{
  //入力する文字列の長さ
  char in1[200],in2[200];
  
  int n1,n2,i,handan;

  while(1){
      //文字列の初期化
      for(i = 0; i < 16; i++){
        in1[i] = 0;
        in2[i] = 0;
      }
      
      //文字列の長さを取得
      input(in1, 1);
      n1 = strlen(in1);

      input(in2, 2);
      n2 = strlen(in2);

      /*
      printf("in1 = %s\n", in1);
      printf("in2 = %s\n", in2);
      printf("hairetu1 = %d\n", n1);
      printf("hairetu2 = %d\n", n2);
      */

      //結合した文字列の表示
      printf("結合された文字列は\n");
      joint(in1,n1,in2,n2);
      printf("です\n");
      
      //再度受付 終了受付
      printf("もう一度やりますか?\n");
      printf("Yesなら1を、Noなら0を入力してください.\n");
      scanf("%d" , &handan);

   while(handan != 1 && handan != 0){
   	printf("1か0を入力してください.\n");
   	scanf("%d", &handan);
   }

      //0ならループ終了。
      if(handan == 0) break;

  }
      return(0);

}
 
あと出来ない点が二つあります。
・文字数を20字にしているにも関わらず全角文字数が10文字ではなく6文字しか入力できない。
(文字コードが関係しており、全角だとバイト数が多く6文字しか入力できないのはわかるが解決策がわからない)

・講師の方に「scanfは使うな」と言われてしまいましたが、scanf以外の処理方法がわからない。

本当にプログラミングの右も左もわからない初心者ですが、何卒ご指摘助言よろしくお願いいたします。

かずま

Re: 入力処理のプログラム

#2

投稿記事 by かずま » 11年前

マーチ さんが書きました: ・空白を入力、または何も入力しない場合、注意文を表示させたい。(文字数が多すぎますと同様に)
空白:スペースが入っています。
何もなし:文字を入力してください

コード:

#include <stdio.h>
 
int main(void)
{
    char s[256];
    scanf("%s", s);
    printf("%s\n", s);
    return 0;
}
このプログラムを実行して、
スペース、スペース、Enter、Enter、a、b、c、Enter
と、入力してみてください。
abc
と表示されます。

scanf の "%s" という書式は、空白(スペースやタブや改行文字)を
読み飛ばした後、空白でない文字が 1文字以上続くものを読み込みます。
ということで、スペース、Enter で、スペースだけを読み込むとか、
Enter だけで、何もない入力を受け付けるとかはできません。
そこで、行単位の入力である fgets の利用を考えてください。
fgets は、改行文字の '\n' までを読み込むことに注意してください。
マーチ さんが書きました: ・最後の「1か0を入力してください」で数字以外の文字を入力すると無限ループに入ってしまうのを、
「1か0を入力してください」と一行のみ表示させ、再度1か0を入力できるようにしたい。
fgets を使ってください。
マーチ さんが書きました: あと出来ない点が二つあります。
・文字数を20字にしているにも関わらず全角文字数が10文字ではなく6文字しか入力できない。
(文字コードが関係しており、全角だとバイト数が多く6文字しか入力できないのはわかるが解決策がわからない)
学校で課題をやるということは、
OS に Linux(Ubuntu など)を使い、
コンパイラに gcc を使っているのでしょう。
こういう環境では、Windows を使っていて
文字コードが Shift-JIS であるのとは違って、
文字コードが Unicode の UTF-8 であることが普通です。

平仮名や漢字などの文字は、
文字コードが Shift-JIS だと 2バイトですが、
UTF-8 だと 3バイトになります。

strlen はバイト数を数える関数であって、文字数は数えてくれません。
解決策は、ほかの問題が解決してからにしましょう。
マーチ さんが書きました: ・講師の方に「scanfは使うな」と言われてしまいましたが、scanf以外の処理方法がわからない。
fgets を使ってください。

マーチ

Re: 入力処理のプログラム

#3

投稿記事 by マーチ » 11年前

かずまさんありがとうございます!

fgetsなどで改めて書きましたがまだ解決できていない点があります。

・文字数が超過するとメッセージは出るようになったが、次の入力に行ってしまうのを戻したい。

・文字列の入力時、スペースに反応するようになったがスペース分メッセージが出るのを直したい。

・全角の処理がわからない。今は*/で処理しないようにしているが、全角の処理のために_ismbbleadを利用しているがエラーが起きてしまう。
全角を処理できるようにしたい。

コードを記載させていただきます。

コード:

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

void input(char in[], int n)
{
 char tmp;
 int i, j;

 printf("%dつ目の文字を入力してください(半角50字、全角25文字以内)\n", n);


 tmp = getchar();
 // 最初の入力が半角のとき
 //if(!(_ismbblead(tmp))){
  // 改行でもスペースでもなかった場合
  if(tmp != '\n' && tmp != ' '){
   // まず文字列 in の先頭に入力した文字を格納し
   in[0] = tmp;
   // 改行かスペースが入力されるまで入力を続け、
   // 文字列 in に先頭のひとつ後ろから格納する。
   for(i = 1; (tmp = getchar())!= '\n' && tmp != ' '; i++){
    in[i] = tmp;
    if(i > 50){
     printf("文字数が50文字を超えています.\n");
     printf("もう一度文字を入力してください.\n");
     // 文字列 in を初期化する。
     for(j = 0; j < 50; j++){
      in[j] = 0;
     }
     i = 1;
    }
   }
   // 最後に終端文字を入れる。
   in[i] = 0;
  }
  // 改行またはスペースだった場合
  else{
   // 改行またはスペースの間入力を繰り返す。
   while(tmp == '\n' || tmp == ' '){
    printf("もう一度入力してください.\n");
    tmp = getchar();
    in[0] = tmp;
   }
   for(i = 1; (tmp = getchar())!='\n' && tmp != ' '; i++){
    in[i] = tmp;
    if(i > 50){
     printf("文字数が50文字を超えています.\n");
     printf("もう一度文字を入力してください.\n");
     for(j = 0; j < 50; j++){
      in[j] = 0;
     }
     i = 1;
    }
   }
   in[i] = 0;
  }
 }
 // 全角のとき
 /*else{
  if(tmp != '\n' && tmp != ' '){
   in[0] = tmp;
   for(i = 1; (tmp = getchar())!= '\n' && tmp != ' '; i++){
    in[i] = tmp;
    if(i > 25){
     printf("文字数が25文字を超えています.\n");
     printf("もう一度文字を入力してください.\n");
     for(j = 0; j < 25; j++){
      in[j] = 0;
     }
     i = 1;
    }
   }
   in[i] = 0;
  }
  else{
   while(tmp == '\n' || tmp == ' '){
    printf("もう一度入力してください.\n");
    tmp = getchar();
    in[0] = tmp;
   }
   for(i = 1; (tmp = getchar())!='\n' && tmp != ' '; i++){
    in[i] = tmp;
    if(i > 25){
     printf("文字数が25文字を超えています.\n");
     printf("もう一度文字を入力してください.\n");
     for(j = 0; j < 25; j++){
      in[j] = 0;
     }
    i = 1;
    }
   }
   in[i] = 0;
  }
 }
*/


void joint(char in1[], int n1, char in2[], int n2)
{
	//outの関数 文字列の格納
    char *out;
    
    int i,j,k;
    //ヒープメモリの確保
    out = (char *)malloc(sizeof(char) * (n1 + n2 + 1));

    //繰り返しで配列 1つ目の文字数終わったら
    for(i = 0; i < n1; i++)
        out[i] = in1[i];

    //空白を入れる
    out[i] = ' ';

    //2つ目の文字列の配列を入れる
    j = i+1;
    for(k = 0; k < n2; k++){
        out[j] = in2[k];
        j++;
    }

    //2つ目の文字列以降は何も入れない
    out[j] = 0;

    //outの配列を表示
    printf("%s\n", out);

    //ヒープメモリの解放
    free(out);
}

int main(void)
{
  //入力する文字列の長さ
  char in1[50], in2[50], handan[50];
  int n1, n2, n3, i;

  while(1){
	
      //文字列の初期化
      for(i = 0; i < 50; i++){
        in1[i] = 0;
        in2[i] = 0;
      }
      
      //文字列の長さを取得
      input(in1, 1);
      n1 = strlen(in1);

      input(in2, 2);
      n2 = strlen(in2);

      /*
      printf("in1 = %s\n", in1);
      printf("in2 = %s\n", in2);
      printf("hairetu1 = %d\n", n1);
      printf("hairetu2 = %d\n", n2);
      */

      //結合した文字列の表示
      printf("結合された文字列は\n");
      joint(in1,n1,in2,n2);
      printf("です\n");
      
      //再度受付 終了受付
      printf("もう一度やりますか?\n");
      printf("Yesならyを、Noならnを入力してください.\n");
   fgets(handan, sizeof(handan), stdin);

   while(handan[0] != 'y' && handan[0] != 'n'){
    printf("yかnを入力してください.\n");
    fgets(handan, sizeof(handan), stdin);
   }
      if(handan[0] == 'n') break;

  }
      return(0);
}

 
よろしくお願いいたします。

かずま

Re: 入力処理のプログラム

#4

投稿記事 by かずま » 11年前

マーチ さんが書きました: fgetsなどで改めて書きましたがまだ解決できていない点があります。
fgets だけでよいと思うのですが、getchar を使ったんですね。
マーチ さんが書きました: ・文字数が超過するとメッセージは出るようになったが、次の入力に行ってしまうのを戻したい。
文字数が超過すると、
in[] をすべて 0 クリアしていますね。
そして、i を 1 にして、for文の最後に戻り、
i++ で i は 2 になります。
超過分は in[2] 以降に入ります。
in[0] と in[1] は 0 のままです。
そして、'\n' で超過分の入力が完了すると、
main に戻りますが、
in[0] が 0 ですから、文字列のバイト数は 0 です。

さらに、半角50文字を許すのなら、最後の '\0' を
含めて、char in1[51], in2[51] でないといけませんし、
超過の判定も if (i >= 50) ですよね。
マーチ さんが書きました: ・文字列の入力時、スペースに反応するようになったがスペース分メッセージが出るのを直したい。
41~45行目で、そうなるように書いていますよね。
マーチ さんが書きました: ・全角の処理がわからない。今は*/で処理しないようにしているが、全角の処理のために_ismbbleadを利用しているがエラーが起きてしまう。
_ismbblead は Windows の VC++ の関数ではないのですか?
Linux の gcc を UTF-8 で使っているのではないのですか?
OS や コンパイラなどの環境を教えてください。
マーチ さんが書きました: 全角を処理できるようにしたい。
バイト数でなく文字数を数える参考プログラムです。
なお、fgets は '\n' まで読み込み、それも文字数に入っています。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>

int main(void)
{
    char buf[1024];
    setlocale(LC_CTYPE, "");
    while (fgets(buf, sizeof buf, stdin)) {
        size_t n = mbstowcs(NULL, buf, 0);
        printf("%u\n", n);
    }
    return 0;
}

かずま

Re: 入力処理のプログラム

#5

投稿記事 by かずま » 11年前

もう提出期限を過ぎてしまったはずですが、どうなりましたか?

こんなプログラムを書いてみましたが、
本当に setlocale を使うような課題が出されるのか、疑問です。

コード:

#include <stdio.h>  // printf, puts, fgets
#include <stdlib.h> // mbstowcs
#include <string.h> // strchr, strcpy
#include <locale.h> // setlocale

#define SIZE 20

int input(char *str, int size, int n)
{
    char buf[1024], *p;  int len;

    printf("%dつ目の文字を入力してください(半角全角合わせて%u文字以内)\n",
        n, size);
    while (fgets(buf, sizeof buf, stdin)) {
        if (p = strchr(buf, '\n')) *p = 0;
        if (strchr(buf, ' '))
            puts("スペースが入っています. もう一度入力してください.");
        else if ((len = mbstowcs(NULL, buf, 0)) == 0)
            puts("文字を入力してください.");
        else if (len > size)
            puts("文字数が多すぎます. もう一度入力してください.");
        else
            return strcpy(str, buf), 0;
    }
    return 1;
}

int main(void)
{
    char s1[SIZE*6 + 1], s2[SIZE*6 + 1], confirm[256];

    setlocale(LC_CTYPE, "");
    while (1) {
        if (input(s1, SIZE, 1)) return 1;
        if (input(s2, SIZE, 2)) return 1;
        printf("結合された文字列は\n%s %s\nです\n", s1, s2);
        puts("もう一度やりますか?\n"
             "Yesならyを、Noならnを入力してください.");
        while (1) {
            if (!fgets(confirm, sizeof confirm, stdin)) return 1;
            if (confirm[0] == 'n') return 0;
            if (confirm[0] == 'y') break;
            puts("yかnを入力してください.");
        }
    }
}

マーチ

Re: 入力処理のプログラム

#6

投稿記事 by マーチ » 11年前

返答が遅くなりすみません。
提出期限は過ぎてしまいましたが、誤作動もなく動かすプログラムができました、ありがとうございます。

ただ全角の処理は結局できずに提出はしてしまいましたが・・・
他の処理の方法がわからないので暫定的に_ismbbleadを利用していました。gccでは扱えないのですね・・・

返答ありがとうございました!また新たな課題も出てきたためまた書き込むかもしれません。
提出も終えたため解決とさせていただきます、ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る