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

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

ただいまの
回答率

90.98%

  • C

    3085questions

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

c言語 コード読み解き方法

解決済

回答 5

投稿

  • 評価
  • クリップ 1
  • VIEW 230

GokaTokyo

score 34

挫折中、早めにコードを理解する方法ありますか?
例えば、下記コードに何するか、そのロジック全部わかりません。(泣)    

#include<stdio.h>
#include<math.h>
#define MAX 1000


int prime[MAX];

int isPrimeNaive(int n)
{
    if(n <= 1)
        return 0;
    for(int i = 2; i < n; i++)
        if(n % i == 0)
            return 0;
    return 1;
}

int isPrime(int n)
{
    if(n<= 1)
        return 0;
    if(n == 2)
        return 1;
    if(n%2 == 0)
        return 0;
    int limit = (int)sqrt((double)n);
    for(int i = 3; i <= limit; i=i+2)
    {
        if(n % i == 0)
            return 0;
    }
    return 1;
}

void sieve()
{
    prime[0] = 0;
    prime[1] = 0;
    for(int i = 2; i < MAX; i++)
        prime[i] = 1;
    int limit = (int)sqrt((double)MAX);
    for(int i = 2; i <= limit; i++)
    {
        if(prime[i])
            for(int j = i*i; j <= MAX; j+=i)
                prime[j] = 0;
    }
}

int isPrimeSieve(int n)
{
    if(prime[n])
        return 1;
    else
        return 0;
}

int main()
{
    sieve();
    printf("N=%d %d\n", 1, isPrime(1));
    printf("N=%d %d\n", 2, isPrime(2));
    printf("N=%d %d\n", 3, isPrime(3));
    printf("N=%d %d\n", 4, isPrime(4));
    printf("N=%d %d\n", 7, isPrime(7));
    printf("N=%d %d\n", 9, isPrime(9));
    printf("N=%d %d\n", 13, isPrime(13));
    printf("N=%d %d\n", 17, isPrime(17));
    printf("N=%d %d\n", 100, isPrime(100));
    printf("N=%d %d\n", 23, isPrime(23));
    printf("N=%d %d\n", 1, isPrime(1));
    return 0;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 5

+2

理解できない場合は、次の2つのうちのどちらか、または両方が足りないので、足りるようにして下さい。
・C言語の理解
・扱っている題材の理解

例えば、将棋のプログラムを読んで理解する場合、将棋の知識が必要です。
これは素数のプログラムのようなので、素数の知識(ある数が素数かどうかをどうやって判断するかレベルの知識で十分)が必要です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/10 22:45

    失礼します。
    このisPrime()って数学で出てきますよね。(数Aかな)

    数学の理解も必要になってくるのではないですかね?
    不要ですかな?

    キャンセル

  • 2017/12/10 22:48

    素数の知識が必要と書いていますよ。

    キャンセル

  • 2017/12/10 23:14

    あ、こりゃ失礼しました。
    またやってしまった。

    キャンセル

checkベストアンサー

+1

コード読み解き方法

複雑だから分かりにくい。
分けると分かりやすい
だから、分かるまで分解します。

C言語は関数が基本的な単位ですので、
ひとつの関数だけを見てみましょう。

int isPrime(int n)

まず、関数名が「Prime」だから、素数を求める関数だと分かります。

int isPrime(int n)
{
        return 0;
        return 1;
        return 0;
            return 0;
    return 1;
}

次に、Return文だけ見ると、返り値は0か1の二択だと分かります。
引数がintで、返り値が0か1の関数。

int isPrime(int n)
{
    if(n<= 1)
    if(n == 2)
    if(n%2 == 0)
        if(n % i == 0)
}

そして、IF文だけ見ると、引数nに応じて分岐している。
正の整数か、2かどうか、剰余が0かによって分岐しています。

int isPrime(int n)
{
    if(n<= 1)
        return 0;
    if(n == 2)
        return 1;
    if(n%2 == 0)
        return 0;
}

前半の方が後半よりやさしいので、前半だけ見てみます。

負数やゼロだと0を返す。
引数nが2だと返り値1を返している。
偶数だと0を返す。
だから、素数だと1で、素数でないと0を返すと分かります。

    int limit = (int)sqrt((double)n);
    for(int i = 3; i <= limit; i=i+2)

後半、一番ゴチャゴチャして難しいところなので、
一行をさらに分けて考えます。

    limit = ;
    for(; i <= limit;)

「limit」はFor文の上限値だと分かります。

sqrt()

「sqrt」は平方根を求める関数です。
だから、For文では、3からnの平方根まで、2ずつ増やして回している。
そういうループ構造が分かります。

関数の中は、IFの分岐とForのループが基本構造です。
それらが複雑な場合、フローチャート図解するのも有効です。

なぜ、平方根を使っているのかは、
「素数 平方根」で検索して、
今回の仕様である数学の知識を得ると分かります。

そしてまた、上から逐次で一行ずつ読むと、
初見の時より、かなり分かりやすくなっていると思います。

今回はmain関数にすでに書いてありますが、
テストを書いて動作を確認するのも大事です。


早めにコードを理解する方法

「毎回こんなことやってたら遅いでしょ」と思うかもしれません。

慣れてきたら、こんな風に読む必要はなくなります。
しかし、最初のうちは、一行ずつていねいに読みます。

「かけ算の九九」とかを覚えるのと同じで、
基礎をやるときは、ゆっくり時間をかけた方が、最終的に早く済みます
「急がば回れ」、「ウサギとカメ」の話です。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

コード読解大原則(でっち上げ)

1. 関数を見たらまず呼び出されているか確認スべし。例えばisPrimeNaiveisPrimeSieveは呼ばれていない。

  1. 関数ごとに、引数で渡されてくる入力、引数ではない形で入ってくる(グローバル変数、標準入力など)入力、戻り値(出力)、引数経由で返される出力(ポインタを介して)、引数ではない形の出力(グローバル変数、標準出力など)を調べる。
  2. 関数の呼び出し箇所を見て入力と出力がどう作られ利用されるか確認する。
  3. 変数名を辞書を引くとかして処理のヒントを得る

今回の場合は素数探索ですね。isPrimeに渡される引数が素数なら1、そうでなければ0を返します。

isPrimeNaiveisPrimeSieveは呼ばれていませんが、isPrimeと引数・戻り値の型が同じで名前も似ているので別のアルゴリズムで同じ結果を得るためのものとわかります。isPrimeSieveはグローバル変数であるprimeを参照しており、呼び出し前にこれを適切に初期する必要があることがわかり、それをしているのがsieve関数ですね

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

細かく(例えば分岐ごとに)printfを挟んで変数が、その時どうなっているかを調べる

最終手段
ソースレベルデバッガを使ってステップ実行し、変数の動きを調べる

慣れてくると自分の頭のなかにCインタプリタが出来上がる

解析しながらコメント書いてくのもいいよ

// nは素数?
int isPrime(int n)
{
    // 1 未満は素数ではない
    if(n<= 1)
        return 0;
    // 2は素数
    if(n == 2)
        return 1;
    // 2を除く偶数は素数ではない
    if(n%2 == 0)
        return 0;
    // 3 ~ x ~ sqrt(n)で割り切れるnは素数ではない
    int limit = (int)sqrt((double)n);
    for(int i = 3; i <= limit; i=i+2)
    {
        if(n % i == 0)
            return 0;
    }
    // 3~sqrt(n)までで割り切れない数は素数
    return 1;
}
// 篩
void sieve()
{
    // 0と1は素数ではない
    prime[0] = 0; prime[1] = 0;
    // 2以上の数には素数の疑惑がある
    for(int i = 2; i < MAX; i++)
        prime[i] = 1;
    // 素数でない数N(MAX以下)はsqrt(MAX)までの素数で割り切れる筈
    int limit = (int)sqrt((double)MAX);

    for(int i = 2; i <= limit; i++)
    {
        // i は疑惑が残っているなら素数
        if(prime[i])
            // i * i 以上のiの倍数は素数ではない
            // (それ未満のiの倍数は既にフラグ消去済み)
            for(int j = i*i; j <= MAX; j+=i)
                prime[j] = 0;
    }
}

// 篩で残ったものは素数
int isPrimeSieve(int n)
{
    if(prime[n])
        return 1;
    else
        return 0;
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

一般論でいうと、コードの読解とは文章問題を解くのと同じです。明確に意図がある記述をされたコードから意図を読み取るのですから、文章読解よりは慣れれば簡単です。

ただ、プログラムの場合はその意図が「何らかの動作をさせること」であり、ものによってはその動作についての知識がないと意味が解けないというのがあります。

関数 isPrime の動作を書き記すと、

  1. 与えられた引数が 1以下 の場合は 0 を返す
  2. 与えられた引数が 2 の場合は 1 を返す
  3. 与えられた関数が 2で割り切れる(=2以外の自然数である偶数) 場合は 0 を返す
  4. 上記 1~3 に当てはまらない(3以上の奇数)は、
    その数の平方根までの整数で順次割ってみて、割り切れる数がある場合は 0 を返す
    割り切れなかったら 1 を返す

となります。が、これがイコール素数を求めるものである、というのは、素数とはどういうものかを知らなければ回答できないわけです。
ですからプログラムを読解する場合、まずそのプログラムがどういう用途で使われるために作られたものであるかを知らないと、正しく解釈することができません。誰であれ、自分の知識にないものは解釈できないのですから。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

  • 解決済

    素数のカウント 高速化

    nを読み込み、n~2nまでの素数の数を求めるプログラムを考えています。 <入力> 1 100 10000 1000000 0 <出力> 1 21 1033 8392 以下のプロ

  • 解決済

    C言語で素数を判定したい

    C言語のプログラムについての質問です。 a^b-cの式の変数を変更して、算出された値が素数なのかどうかをエラトステネスのふるいで 判定するプログラムを書こうとしています。 例

  • 受付中

    解決策が分かりません・・・

    5人の点数をキーボードから読み込んで、合計点、平均点、最高点、最低点を表示したいのですが(点数は0以上100以下)、 実行例 5人の点数を入力してください。 1番:95 2

  • 解決済

    結果の表示について

    課題で、 キーボードから入力された数値の平均を計算して表示し、平均以上の数値、平均より小さい数値を表示するプログラムを考えているのですが、 実行例 ./a.out

  • 解決済

    配列

    n個のデータを配列に読み込み、平均と分散を求めるプログラムを作成して、下記のデータで試せ、という問題です。 {3.9,10.4,9.5,7.5,2.8,4.8,2.9,8.1,3

  • 解決済

    「素数の足し算で」の解き方を教えてください

     はじめに いつもお世話になっております。 件名の解き方についてアドバイスを下さい。 これはCodeIQに投稿されていた問題だったのですが、どうしても解けませんでした。

  • 解決済

    文字列のプログラムについて

    Cを使って3つの文字列を入力し一番文字数が最多の文字列を出力する(ただし最多の数と同じ数の文字列がある場合同じ数の文字列をすべて出力) というプログラムを作っているのですが今文字数

  • 解決済

    素数の判定(1または2が入力されたら、入力をやり直させる)

    前提・実現したいこと 素数であるかどうかを判定するプログラムを作成したいのですが、”入力された数を引数とする関数を作成する”では、何の関数を使えばいいかわかりません。 また、”素数

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

  • C

    3085questions

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