黒馬プログラマー-C言語基礎編-マクロ定義、配列、文字列、関数

6233 ワード

---Javaトレーニング、Androidトレーニング、iOSトレーニング、.Netトレーニングはあなたと交流することを期待します!------
本編では、マクロ定義、配列、文字列、関数という簡単なC言語の小プログラム問題を通じて、今日のトピックを導入します.まず私たちのテーマを見てみましょう.
*キーボードから大量の文字列を入力し、A、B、C、Dの出現回数を統計し、最後の出現回数は高から低出力までのアルファベットと出現回数である.
この問題は私から見れば3つの機能モジュールに分けることができます:文字列を入力して、統計回数、並べ替えて出力して、これは私たちの主な関数の構造を決定しました
まずコードヘッダを見てみましょう
#include 
#include 
#define M 100
#define N 4

includeはプログラムで使用する関数を含むヘッダファイルですdefineこれは前処理命令のマクロ定義です
この問題では、パラメータなしの定義を使用します.
#defineマクロ名文字列(注意:末尾は[;])を使用しない)
つまり、プログラムではマクロ名を使って右の文字列の内容を表しています.マクロ定義とは、実はプログラムの実行前にコンパイルするときに、マクロ名を右の文字列に置き換えて、その後の操作を行うことです.個人的には、これが最も一般的な使い方だと思います.ここでは、パラメータ付きマクロ定義の使い方を紹介します.
次のコードはテーマに関係なく、マクロ定義としての使用方法の補足です.
#include 
#define TEST(a) a * a
int main()
{
    int r = TEST(2+2);
    printf("%d
",r); }

結果は4
しかしこのマクロ定義には問題があり、TEST(2+2)になると結果は16ではなく8となる.これはマクロ定義が純粋な置き換えであり、関数のように計算ができないためである.TEST(2+2)は2+2*2+2に置き換えられ、結果は自然に8であるため、定義の際に変数に()をつける必要があるが、それでも足りず、結果に()を付ける必要がある
改良されたコード(以下のコードはテーマに関係なく)
#include 
#define TEST(a) ((a) * (a))
int main()
{
    int r = TEST(5+5)/TEST(2+3);//               
    printf("%d
",r); }
は私たちのテーマに戻ります.以下はmain関数のコードです.上記に対応して、3つのモジュールに分かれています.
int main()
{
    int count[N] = {0};
    //               ,       
    char *input = (char *) malloc(M);
    printf("      :
"); //gets() warning, , gets(input); // Statistics(input,count); // Sort(count); return 0; }

このコードから、配列、文字列、関数という今日のトピックを見つけることができます.次に、彼らの使い方を簡単に説明します.
1.配列
配列の格納は実際にはデータ構造でいう線形テーブルであり,すなわちヘッダアドレスから各配列要素が順次後方に格納される.
配列の宣言:タイプ配列名[下付き];
例えば上述のint count[N]={0};
配列については、次の点に注意してください.
(1)配列名は配列ヘッダのアドレスを表す(これは配列をパラメータとして関数に渡す際に注意すべきであり,上記コードのSort(count)は,このような使い方である).
(2)

グループ
の初期化は


グループ


なお、上記コードのint count[N]={0}このように、このコードをプログラミングの下のコードから外すと
 int count[N];
count[N]={0};
これは間違いです.コンパイルするときは間違いを報告しますので、注意してください.
(3)

ひょうじ
の位置は定数でしか使えません
へん
量、皆さんはきっとこのコードがint count[N]={0};これは変数Nを使ったのではないでしょうか.注:これは上のマクロ定義で、値は4で、変数ではありません.変数を下付きとして定義すると、コンパイル時にもエラーが表示されますが、マクロ定義は問題ありません.プログラムの実行時に定数になります.
(4)C言語で配列に格納されるのは,統合型のデータのみである.
2.文字列
文字列は、その名の通り「一連」の文字であり、文字ストリームであり、'0'で終わり、'0'の役割は文字列の終わりを識別するために使用され、これは%sで文字列を出力する際に役立ちます.
次のコードはテーマに関係なく
int main()
{
    char *input = "";
    input = "hello world";
    printf("%s
",input); return 0; }

文字列の定義はchar*でなければならないが、実際には文字配列ではなくポインタであり、文字配列よりも多くなっている['0'].
文字列を%sで出力する場合、"0"に遭遇すると出力を停止し、文字配列を定義すると
char input[100] = {}; ,'0'がないため、'0'に出会うまで、先頭アドレスから出力文字が1つずつ出力されます.しかし、そう書けばchar input[100]={'0'}で大丈夫です.
このセグメントのコードでは、このコードchar*input=(char*)malloc(M);これは、画面から入力文字列を受信する文字列変数を定義すると、まだ記憶領域が割り当てられておらず、使用できないため、この文で記憶領域を割り当てることで、mallocという関数にstdlibが含まれているため、後の使用は全く問題ありません.h. もう一つ注意しなければならないことがあります.
文字列の長さを計算します(文字数ではなくバイト数を指します.例えば、1つの漢字が3バイトを占め、その長さは1ではなく3です).
sizeof()出力文字列内のすべてのバイト数('0'を含む)
strlen()は、文字列内のすべての文字数を出力します.'0'は含まれません.
3.関数
関数は実は1段の機能コードをカプセル化して、使う必要がある時パラメータの呼び出しに伝わります(あるいは伝わりません)
関数は使用する前に宣言する必要があります.慣習的には主関数の前に書きます.関数全体が主関数の前にある場合は、単独で宣言する必要はありません.
//       
void Statistics(char *in,int c[]);
//      
void Sort(int c[]);

デフォルトでは外部関数(extern)、つまり他のファイルでも使用できますが、本ファイルの使用に制限されている場合はvoidの前にキーワードstaticを付ける必要があります
voidは戻り値がないことを示し、戻り値がある場合はint、doubleなどに必要なタイプに変更する必要があります
()内は入力するパラメータを表し、実パラメータ、局所変数
次のコードはテーマに関係なく
void test(int a)
{
}
に入力されたパラメータは基本データ型であり、これは値伝達を行い、元の変数の値を実パラメータに伝達するだけで、この値を変更しても、元の変数の値は変更されません.
もう一つは住所、つまり私たちが練習しているコードです.
//    :        ,  A、B、C、D     
void Statistics(char *in,int c[])
{
    //     
    while (*in != '\0')
    {
        //  A、B、C、D     
        if (*in >= 'A' && *in <= 'D')
        {
            c[*in - 'A']++;
        }
        in++;
    }
}

ここでの2つのパラメータはいずれもアドレス伝達,すなわち主関数中の文字列と配列のアドレスをパラメータとして伝達するので,関数でその値を修正することは可能である.
この小さなコードにはwhile(ループ終了の条件)が使われています.
ループ構造とif分岐構造は、回数を統計する際に小さなテクニックがあります.それは配列の下付き文字に*in-'A'を使用しているので、分岐文で判断して再統計する必要はありません.c[0]はAの回数を表し、c[1]はBの回数を表し、c[2]はCの回数を表し、c[3]はDの回数を表し、cはcountを指すので、このときcountの値も対応しています.ここで入力文字列の遍歴はポインタにより,ヘッダアドレスから*inで各文字にアクセスし,in++はポインタが次の文字に移動することを示す.
ここで注意すべき点は,本セグメントコードのcをsizeofで計算すると,我々が以前主関数で呼び出した結果とは異なり,得られたのは8バイトであり,ここではポインタとなっているのでsizeofを用いて配列長を計算するには,主関数で行うことが望ましい.
//    :      ,   
void Sort(int c[])
{
    //          
    struct NewSort
    {
        char c;
        int times;
    };
    //       
    struct NewSort out[N];
    //          
    for (int i = 0; i < N; i++)
    {
        out[i].c = 'A' + i;
        out[i].times = c[i];
    }
    //      (    )
    for (int i = 0; i < N; i++)
    {
        for (int j = i + 1; j < N; j++)
        {
            if (out[j].times > out[i].times)
            {
                struct NewSort t;
                t = out[j];
                out[j] = out[i];
                out[i] = t;
            }
        }
    }
    //              
    for (int i = 0; i < N; i++) {
        printf("%c\t%d
",out[i].c,out[i].times); } }

これは最後のコードです.中には構造体があります.構造体は実際には異なるタイプのデータセットを複雑なデータ型に合成し、基本的なデータ型、ポインタ、構造体をネストすることができます.
について
こうぞう
体が占める存在
貯蔵する

採用する
そろえる
アルゴリズム(
配置
アルゴリズム)、つまり
こうぞう
体占有の存在
貯蔵する


そのとおりである

の最大値
へん

長い
度の倍数.例えば、上記のコードで定義された構造体NewSortは、本来の長さは1(char)+4(int)=5バイトであるべきであるが、整列アルゴリズムによりint型バイトの倍数、すなわち8バイトに補完される.
struct NewSort out[N];この文は、上記の構造体宣言を使用して出力用の構造体配列を作成し、forループ文を使用して値を割り当てます.
最後のバブルソートは,二重ネストサイクルを用いて,最初の要素から後のすべてのデータを比較し,後のデータが現在のデータより大きい場合,2つの要素を交換した.
最後に、ソートした配列を印刷します.
ここでは、出力用の配列を再定義するのは、入力の値が変わらないこと、つまりデータソースが変わらないことを保証するためです.もちろん、入力と出力は同じ配列で実現する上では全く問題ありません.