質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • C

    3977questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

スペース区切りの文字列と整数の読み取り

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 914

thoifon

score 4

-入力-
N
都市名1 数
都市名2 数

一行目のNがその後何行要素を読み込むか決めています。

-入力例-
2
tokyo 12
honoruru 11

-出力例-
tokyo
12
honoruru
11

stockにstrで読み取った要素の「都市名」を、minにnumで読み取った要素の「数」をコピーしています。
for文の後、読み取った都市名と同じものを表示するようにしています。

配列を「都市名」と「数」で2つ宣言しているのは冗長であるとおもいます。
何か他に書き方があれば教えていただきたいです。

以下私の書いたコードです。

#include <stdio.h>
int main(void){
    int N;
    scanf("%d", &N);
    char str[N+1], stock[N];
    int num[N], min[N], tmp;
    for (int i=0; i<N; i++) {
        scanf("%s", &str[i]);
        stock[i] = str[i];
        scanf("%d", &num[i]);
        min[i] = num[i];

        printf("%s\n", &str[i]);
        printf("%d\n", num[i]);
    }
    return 0;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • raccy

    2017/04/02 07:35

    都市名は何文字以下という制限はないのですか?無制限の文字列受け取りはC言語だととても面倒似なるのですが…。あと、VC++でも動くようにする(VLAが使えない)と言う縛りも無しで良いでしょうか?

    キャンセル

  • thoifon

    2017/04/02 11:23

    今回は実在する都市名を対象としていますのでchar型で扱えるサイズの文字列を想定しています。VC++を存じ上げませんが、無しで良いかと思います

    キャンセル

回答 3

checkベストアンサー

+2

配列を「都市名」と「数」で2つ宣言しているのは冗長

「数」についてはそうですね。またそれぞれを配列として宣言するより構造体としてまとめた方がよいという観点もあります。しかし元のコードでは「都市名」については、冗長云々より先に正しくない実装になっていますのでその点をコメントします。

  • 配列の宣言(固定サイズ、可変サイズ)
    もし配列の要素数Nが固定(定数)なら
#define N 10

int min[N];

int main() {
  for (int i = 0; i < N; i++) {
    min[i] = ...; // 配列の要素のアクセス
  }
}


のように書けます。固定サイズの配列はどのバージョンのCでも書けますので基本的な書き方と言えるでしょう。

しかし配列の要素数Nが可変(プログラムを実行する度に値が違うものとなり得る)なら、基本は「mallocにより動的にメモリーを確保する」方法をまず学ぶことをお勧めします。それを意識しているかどうかはっきりしませんが、VLA(variable length array)を使っておられます。しかしコードの完成度からいって自分は質問者さんにまずmallocを使う方法を学ぶことをお勧めします。Nが可変のとき配列を動的に確保するにはCではポインターを使って次のように書きます。

#include <malloc.h>
...
int N;
scanf("%d", &N); // プログラムを実行する度にNは変わる。つまりNは定数ではなく変数
int *min = (int*)malloc(sizeof(int) * N); // mallocで任意の大きさの領域を確保
for (int i = 0; i < N; i++) {
  min[i] = ...; // ポインターminを使ってもあたかも配列のように要素をアクセスできます
}
  • 文字列の長さと個数
    文字列は例えば"abc"であれば最小限、3文字+末尾のNUL文字の合計4個のchar要素を格納できる領域が必要です。また"abc","def"という2つの文字列を格納するには少なくとも4個のchar要素の領域が2セット必要です。しかしあなたのコード上では単に文字列の個数Nに対して要素数をN+1にしています。Nは文字列の個数であって長さではありませんしそもそも長さ×個数の領域が必要という点を配慮できていません。

長さがLの文字列をN個分格納するためには最小でも(L+1)xN個のchar要素が必要です。このような領域は2次元配列として表現したりポインターのポインターとして宣言したりといくつかのバリエーションがありますが、そのような領域を配列やポインターでどう書くべきかは、ある程度の学習が必要です。ここでは詳細は述べず例のみ挙げてみます。(いくつかの箇所ではintでなくsize_tを使うほうがよりよいコードと言えるかも知れませんが以下の例ではintとしています。)

文字列の最大長も文字列の個数も固定とし2次元配列にする場合

#define MAXL 20
#define N 10
char town_names[N][MAXL + 1];

文字列の最大長は固定、文字列の個数は可変の場合

#include <stdio.h>
#include <malloc.h>

#define MAXL 20

typedef char TOWN_NAME[MAXL + 1];

int main() {
  int N;
  TOWN_NAME *town_names;

  scanf("%d", &N);
  town_names = (TOWN_NAME*)malloc(sizeof(TOWN_NAME) * N);
  for (int i = 0; i < N; i++) {
    scanf("%s", town_names[i]);
  }
  ...
}


文字列の最大長も文字列の個数も可変としたい場合

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

// 個々の文字列の長さは可変とするがこの例では読み込みの際のバッファー長は固定としておく
#define MAXL 20

int main() {
  int N;
  char **town_names;
  char buffer[MAXL + 1];

  scanf("%d", &N);
  town_names = (char**)malloc(sizeof(char*) * N);

  for (int i = 0; i < N; i++) {
    scanf("%s", buffer);
    int town_name_len = strlen(buffer);
    town_names[i] = (char*)malloc(town_name_len + 1);
    strcpy(town_names[i], buffer);
  }
  ...
}

なお、C言語の仕様は時代の変遷によって変化しているので「ずっと昔から使える機能」と「現在でも一部のコンパイラーでしか使えない機能」が入り混じっています。こうしたことは他の言語でも同様なので回答の際には「何を前提にするか」が回答者の知識や主観に左右されることがあります。自分はVLAをこのサイトで教えていただくまで知らなかった(w;)のですが、知った後でも「多くのCコンパイラーでは使えるとしても基本としてまず知っておくべきことは何か」との観点からVLAでなくmallocを使う方法を述べ、「新しい仕様ではあるが推奨したい書き方」という考えからc99以上で利用できる「変数をブロックの先頭で宣言しなくても使う場所で宣言できる」仕様を前提に回答しています。(それ以外に自分でも気づかない前提を置いている箇所があるかも知れません。)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/08 12:22

    KSwordOfHaste様
    ご回答ありがとうございます。

    「mallocにより動的にメモリーを確保する」という方法を理解していませんでした。
    配列の動的メモリの確保について勉強しなおしてみます。

    回答の冒頭にもありましたように、今回の場合構造体を使った方が綺麗にまとまる気がします。
    構造体を使った方法も考えてみたいと思います。

    キャンセル

+2

char str[N+1]はたぶん間違いではないかと思われます。

ご参考まで

#include <stdio.h>
int main(void){
    int N;
    scanf("%d", &N);
    char str[N][256];
    int num[N];
    int i;
    for (i=0; i<N; i++) {
        scanf("%s %d", &str[i], &num[i]);

    }
    for (i=0; i<N; i++) {
        printf("%s\n%d\n", str[i], num[i]);
    }
    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

#include <stdio.h>

typedef struct _item item;
struct _item {
    char name[ 100 ];
    int num;
};

int main( void ) {
    int N;
    char buf[ 1000 ] = { 0 };
    item* items;

    fgets( buf, sizeof( buf ), stdin );
    sscanf( buf, "%d", &N );

    items = malloc( sizeof( item ) * N );
    if( !items ) {
        memset( items, 0x00, sizeof( item ) * N );
        printf( "malloc err.\n" );
        return -1;
    }

    /* 取得 */
    for( int i = 0; i < N; i++ ) {
        memset( buf, 0x00, sizeof( buf ) );
        fgets( buf, sizeof( buf ), stdin );
        sscanf( buf, "%s %d", items[ i ].name, &items[ i ].num );
    }

    /* 表示 */
    for( int i = 0; i < N; i++ ) {
        printf( "%s\n%d\n", items[ i ].name, items[ i ].num );
    }

    free( items );
    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C

    3977questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。