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

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

ただいまの
回答率

90.87%

  • C

    3315questions

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

C言語で変数を使わずに配列の中身分ループさせたい

解決済

回答 7

投稿 編集

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

ogura87

score 90

C言語で、変数(ローカル、グローバル共に)を使わずに配列分ループさせて配列の中身を取り出すことは可能なのでしょうか?

例えば、このようなロジックを考えてみたのですが、
いまくいきません。

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

int main(void){

    // 構造体配列に初期値セット
    person1 person[] = {
        {1,2},
        {2,3}
    };

    // for文を初期値なしでpersonのアドレスインクリメントでループ
    for(;person !=null;person++){
        printf("%d\n", person.no1);
    }

}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • maisumakun

    2018/05/24 07:54

    なぜ「ローカル変数を使わずに」やらないといけないのでしょうか。

    キャンセル

  • yohhoy

    2018/05/24 09:15

    あなたの言う「変数」とは何ですか?personは変数ではないという認識でしょうか?

    キャンセル

  • ogura87

    2018/05/26 09:15

    いいえ。personも変数でした。

    キャンセル

  • a_saitoh

    2018/05/28 11:15

    処理すべきデータの入った配列は無しではすみませんよね。それ以外に変数を使わずに、ということですか?

    キャンセル

回答 7

+2

関数を作れば出来るかと思いましたが、関数の仮引数もだめだと言うことだと、無理でしょう。

一応、関数版を書いておきます。

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

void foo(person1 *p, person1 *q){
    if(p<q){
        printf("%d\n", p->no1);
        foo(p+1, q);
    }
}

int main(void){
    person1 person[] = {
        {1,2},
        {2,3},
    };
    foo(person, person+sizeof person/sizeof *person);
}


そもそも仮引数を使って良いなら、

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

int main(int i){
    person1 person[] = {
        {1,2},
        {2,3},
    };

    for(i=0; i<sizeof person/sizeof *person; i++){
        printf("%d\n", person[i].no1);
    }

}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/26 09:25

    うーん、そうですね。。。
    引数でも変数なので。。。

    キャンセル

  • 2018/05/26 12:05

    他の回答へのコメントを見ると、「変数(引数を含む)を使いたくない」じゃなくて、「変数(引数を含む)への明示的な代入・更新を書きたくない」ですか?
    仮引数への実引数の代入はOKということ?

    あるいは、constの付いた変数は変数じゃない扱い?

    キャンセル

checkベストアンサー

+1

(簡単のためサンプルは自前です)例えば、以下のような再帰関数を使うという方法が挙げられます。
これは純粋関数型言語Haskelなどで用いられる方法です。

//ar[]は終端要素0で終わるものとする。
void dumpElement(int ar[])
{
  if(ar[0]){
    printf("%d\n", ar[0]);
    dumpElement(&ar[1]);
  }
}
//または↓の形もあり

void dumpElement(int ar[], int length)
{
  if(0 < length){
    printf("%d\n", ar[0]);
    dumpElement(&ar[1], length - 1);
  }
}

以下追記、
皆さんの回答を見ていると「変数使用しないなんて無理」という意見がありますけれど、変数を使用しない言語も実在します(純粋関数型言語)。もちろん、各定義時に初期値のセットだけは必要ですけれど、値の更新を行わない(定数として扱う)プログラム技法というのも実際にあります。例えばHaskellでは本例のように、再帰を使うことで(C言語でいうところの変数の値の更新を)実現するという手があります。当然ながら、プログラミングに強い制約を課すことにはなりますが、これはこれで一つのやり方と呼べます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/26 09:21

    おお!なんと素晴らしい!
    これならインクリメントを繰り返しながら変数を使わずにループ処理ができますね!
    この方法でやってみます。
    ありがとうございました~

    キャンセル

  • 2018/05/26 09:50

    >しかし、引数でも変数なので。。。と、asmさんの回答に言っていますがdumpElement()の引数はいいのでしょうか?

    キャンセル

  • 2018/05/26 10:56

    ええ、そうなんですが、これならint ar[]の代わりにconstを使ってもいけるなと。

    ん?無理か?

    ちょっとやってみます。

    キャンセル

  • 2018/05/26 14:50

    未確認ですがconst配列にしてもできるはずですよ。

    キャンセル

  • 2018/05/26 16:59 編集

    dumpElement()に渡した時点で、int ar[]はint *pと等価(ポインタは変数)ですから配列の中身を変更しなければconstでもOKです。私が言いたかったのは、「引数でも変数」と言いながらなぜOKなのかが知りたかったのです。
    プロの方が多いと思いますので、こういった事には敏感だと思いますが?

    キャンセル

  • 2018/05/26 17:25

    「指し示す中身の変更をしない。」のみでなく、「指し示す先の変更もしない」ですので、より制限が強い形で実現しています。

    asmさんの回答では「指し示す先の変更」を許容しています。

    キャンセル

+1

C++ならばrange-based forで

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

int main(void){
  person1 person[] = {
        {1,2},
        {2,3}
  };
  for(person1& p : person){
    printf("%d\n", p.no1);
  }
}

出来ます。

どうしてもC言語で変数を使いたくないなら…

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

void for_loop(void* base, void* end, size_t elem_size, void (*func)(void* it)){
  for(;base < end; base += elem_size)
    func(base);
}

void print_person(person1* p){
  printf("%d\n", p->no1);
}

int main(void){
  person1 person[] = {
        {1,2},
        {2,3}
  };
  for_loop(person, person + sizeof(person) / sizeof(*person), sizeof(person1), print_person);
}

引数は変数ではないという言葉遊びの域ですが可能です。

あとは繰り返しの方法について指示がないのでCプリプロセッサを用いる事で可能なようにも思います。


追記
あれ?const修飾したいだけなのかな?

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

int main(void){
    person1 person[] = {
        {1,2},
        {2,3}
    };
    for(const person1 *cur = person, *const end = cur + (sizeof(person) / sizeof(*person));
        cur < end;
        cur++){
        printf("%d\n", cur->no1);
    }
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/26 09:24

    うーん、なるほど。。。
    しかし、引数でも変数なので。。。

    キャンセル

0

グローバル変数を使うということ?


無理ですねー、と言いながら考えてみました

int main(void){

    // 構造体配列に初期値セット
    person1 person[] = {
        {1,2},
        {2,3}
    };
    person1 *p;
    // for文を初期値なしでpersonのアドレスインクリメントでループ
    for(p=person;p<(person+(sizeof(person)/sizeof(*person));p++){
        printf("%d\n", p->no1);
    }

これでどんなもんでしょw

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/24 08:04

    いいえ、グローバル変数も使ってはいけません。

    キャンセル

  • 2018/05/24 08:05

    なら無理ですね

    キャンセル

  • 2018/05/24 08:21

    と言いながら更新しましたw

    キャンセル

  • 2018/05/26 09:36

    うーん、すいません。
    p*も変数なのでそれも使いたくないです。。。

    キャンセル

0

普通に書けば、以下のようになりますが削除したい(使いたくない)のはどれでしょう?

int main(void){

    // 構造体配列に初期値セット
    person1 person[] = {
        {1,2},
        {2,3}
    };

    // for文を初期値なしでpersonのアドレスインクリメントでループ
//    for(;person != NULL;person++){
    // personは配列の先頭アドレスなので左辺値にはなれない。(インクリメント不可)
    for(int i= 0; i < sizeof(person)/sizeof(person1);i++){
        printf("%d\n", person[i].no1);
    }

    return 0;
}


題意とは違うと思いますが、再起を使うと・・・

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

void print(person1 *pp)
{
    if( pp->no1== 0){
        return;
    }
    printf("%d\n", pp->no1);
    //
    print(++pp);
}

int main(void){

    // 構造体配列に初期値セット
    person1 person[] = {
        {1,2},
        {2,3},
        {0,0}
    };

    print(person);

    return 0;
}


「追記」こういったこと?

#include <stdio.h>

typedef struct {
    int no1;
    int no2;
} person1;

void print(const person1 * const pp)
{
    if( pp->no1 != 0){
        printf("%d\n", pp->no1);
        print(pp+1);
    }
}

int main(void){

    // 構造体配列に初期値セット
    person1 person[] = {
        {1,2},
        {2,3},
        {0,0}
    };

    print(person);

    return 0;
}


usr~/test % ./a.out 
1
2
usr~/test % 

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/24 11:48

    仮引数がOKであれば、mainの仮引数を宣言してそれを使えばいいかと。

    キャンセル

  • 2018/05/26 09:28

    この中だと変数iを使いたくないのと、personはconstにしたいです。
    でも、constだと++ができないんですよね。。。

    キャンセル

  • 2018/05/26 10:24

    personは配列の先頭アドレス(固定です)からもともと左辺値にはなりませんd++

    キャンセル

0

 person1 person[] = {
        {1,2},
        {2,3},
        {-1,0}    /* 終わりの印を入れておく */
    };


とかしておいて、

for(p=person; p->no1 >= 0; p++){


じゃ、だめ?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/26 09:22

    ごめんなさい。
    これだとそもそもpが変数なので。。。

    キャンセル

-1

おそらくループ用のカウンタを使わずに、ってことなんでしょうか。
であるなら、構造体の配列のポインタくらいはないと実現できません。
但しそうした場合でも配列の終端が提示コードの情報ではわからないので、ループの終わりが判定できません。

person1 *pperson = (person1*)person;
for( ; /* ここが書けない */ ; pperson++){
    printf("%d\n", pperson->no1);
}

あ、いやアドレス計算すればできるか。

person1 *pperson = (person1*)person;
for( ; pperson < (person + sizeof(person)); pperson++){
    printf("%d\n", pperson->no1);
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/05/24 10:39

    (person + sizeof(person))って、person+16になりませんか?

    キャンセル

  • 2018/05/24 10:44

    なりますね(int型が4バイトの場合)
    ダメですか?

    キャンセル

  • 2018/05/24 10:48

    やってみたらダメでした orz
    自分が何かを勘違いしている…。

    キャンセル

  • 2018/05/24 10:54

    えっと、person+16は、&person[16]と同じですd^^;

    キャンセル

  • 2018/05/24 10:56

    > cateyeさん
    ですね。
    うっかりでした。

    なので、personをキャストすればよさそう。
    ((long)person + sizeof(person))

    キャンセル

  • 2018/05/26 09:35

    すいません。
    personはconstにしたいです。
    そうすると、++できないんですよね。。。

    キャンセル

  • 2018/05/26 12:34

    いえ、personのアドレスをppersonに入れてるでconstでも大丈夫ですよ。

    キャンセル

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

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

関連した質問

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

  • C

    3315questions

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