zoukankan      html  css  js  c++  java
  • C语言 | 基础知识点笔记

    函数

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    //参数传值调用

    在C语言中,被调函数不能直接修改主调函数中变量的值,而只能修改函数私有的临时副本的值

    必要时,也能够修改主调函数中的变量。需要向被调用函数提供待设置值的变量的地址(指针)。被调用函数则需要将对应的参数声明为指针类型,并通过它间接访问变量。

    如果是数组参数,当把数组名用作参数时,传递给函数的值是数组起始元素的位置或地址,并不复制数组元素的本身。在被调函数中,可以通过数组下标访问或修改数组元素的值。

       

    ————————————————————————————————————————————

    变量

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    自动变量(局部变量) //在一个函数开头或段开头处说明的变量

    作用域:

    仅在定义它的函数内;

    初始化:

    不自动赋初值,使用前需要赋值;

    值的保持:

    随函数的引用而存在和消失,不保持值;

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    外部变量(全程变量) //在函数外部定义的变量

    优势:解决函数单独编译的协调;与变量初始化有关;外部变量的值是永久的;解决数据共享;

    作用域:整个程序;

    初始化:0

    值的保持:永久保持

    特点:

    1. c程序可以分别放在几个文件上,每个文件可以作为一个编译单位分别进行编译。外部变量只需在某个文件上定义一次,其它文件若要引用此变量时,应用extern加以说明(外部变量定义时不必加extern关键字)
    2. 在同一文件中,若前面的函数要引用后面定义的外部(在函数之外)变量时,在函数里加extern加以说明。

    举例:

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    静态变量 - 内部 //在局部变量前加上static

    作用域:仅在定义它的函数内;

    初始化:0

    值的保持:当函数执行完,返回调用点时,该变量并不撤销,再次调用时,其值将继续存在;

    特点:采用静态存贮分配(由编译程序在编译时分配,而一般的自动变量和函数形参均采用动态存贮分配,即在运行时分配空间);

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    静态变量 - 外部 //在函数外部定义的变量前加static

    优势:可以实现数据隐藏

    作用域:定义它的文件(该文件的私有变量),其他文件上的函数不允许访问;

    初始化:0

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    寄存器变量 //只有自动(局部)变量和函数参数才能进一步指定为寄存器存贮类

    特点:

    1. 使用register变量可以提高存取速度,但寄存器变量的数目依赖于具体机器,声明多了也只有前几个有效。
    2. 只限于int,char,short ,unsigned和指针类型用寄存类。
    3. 不能对register变量取地址(即&操作)

    ————————————————————————————————————————————

    常量

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    enum 枚举常量

    不同枚举中的名字必须互不相同,同一枚举中不同的名字可以是用相同的值;相对#define来说,优势在于常量值可以自动生成

    举例:

    1. enum week {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};

      /*

      week是新的数据类型,源于int,此时:

      MONDAY = 0

      TUESDAY = 1

      WEDNESDAY = 2

      THURSDAY = 3

      FRIDAY = 4

      SATURDAY = 5

      SUNDAY = 6

      */

    2. enum week {MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};

      /*

      MONDAY = 1

      TUESDAY = 2

      WEDNESDAY = 3

      THURSDAY = 4

      FRIDAY = 5

      SATURDAY = 6

      SUNDAY = 7

      */

    3. enum escapes {BELL = 'a', BACKSPACE = '', TAB = ' ', NEWLINE = 'n', VTAB = 'v', RETURN = ' '};

      /*

      BELL = 'a',

      BACKSPACE = '',

      TAB = ' ',

      NEWLINE = 'n',

      VTAB = 'v',

      RETURN = ' '

      */

    ————————————————————————————————————————————

    关键字

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    const //限定符,通过 const 对变量进行限定后,无法修改其值,数组同理。

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    register //请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率。

    1. register变量必须是能被CPU所接受的类型。这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。
    2. 不能通过 & 来取地址

    ————————————————————————————————————————————

    数组

    注意:数组名即数组的第一个元素的地址,所以使用scanf函数的时候可以不使用 &

    // 调用数组a[i]的值时也可以写成 *(a+i) 的形式,编译的过程实际上先将其转换成 *(a+i) 再求值。所以 a[i] 与 *(a+i) 是等价的,一个通过数组和下表实现的表达式可以通过指针可偏移量实现。注意:指针是一个变量, p=a或p++是合法的,但数组名不是变量,不可以执行上面的操作。

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    字符数组 //scanf在读取字符串的时候不使用取址操作符 &,同指针

    char str[1000];

    scanf("%s",str);

    ————————————————————————————————————————————

    指针

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    地址运算符 & 只能应用于内存中的对象(变量与数组元素)。它不能作用于表达式/常量/register类型的变量。

    取值运算符 * ,在定义指针时表示定义的是个变量,在其他地方表示取指针变量的那个值

    指针只能指向某种特定类型的对象(例外情况:指向void类型的指针可以存放指向任何类型的指针,但它不能间接引用其自身)。

    定义:

    int a;

    int *p;

    p = &a;

    scanf("%d",p);

    printf("%d ",*p);

    //指向数组的普通指针(非数组指针)

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    //char

    char *p;//定义一个字符指针

    char str[1000];//定义一个字符数组

    scanf("%s", str);//字符数组输入

    p = str; //p指针指向str首地址

    printf("%c %c ", *p, *(p + 1)); //打印首地址的值与第二个地址的值

       

    //int

    int a[5] = {1, 2, 3, 4, 5};

    int *q;

    q = a;

    //或写成 int *q = a;

    printf("%d %d ", *q, *(q + 1));

    return 0;

    }

    //指向指针的指针

    定义:

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int num = 520;

    int *p = &num;

    int **pp = &p;//pp为指向指针的指针

    return 0;

    }

    num

    520

      

      

    //int num中存放的值是520

    p

    &num

      

      

    //指针p中存放的是num的地址

    *p

    num

    520

      

    //对指针p解引用得到&num存放的值 == 520

    pp

    &p

      

      

    //pp作为指向指针p的指针,存放的是p的地址

    *pp

    p

    &num

      

    //pp解引用得到的是 p == &num

    **pp

    *p

    num

    520

    //pp二层解引用得到的是 *p == num ==520

    举例:

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    char *str[] = {"aaa", "bbb", "ccc", "ddd", "eee", "fff"};

    //定义这个指针数组,此时指针数组存放的都是指针,字符串是指向字符的指针,数组每个元素都是指针,数组又可以用指针的方式来访问,所以我们可以用指向指针的指针来访问指针数组;

    char **p;//定义指针p为指向指针的指针

    char **str2[4];//str2数组中存放了4个指向指针的指针

    p = &str[5];//p指向"fff",取址得到字符串"fff"的地址,此时p的一个指向字符指针的指针

    str2[0] = &str[0];//str2数组中的指向指针的指针分别指向str数组中的指针

    str2[1] = &str[1];

    str2[2] = &str[2];

    str2[3] = &str[3];

    printf("%s ", *p);

    for (int i = 0; i < 4; ++i)

    {

    printf("%s ", *str2[i]);

    }

    return 0;

    }

    //指向常量的指针 (指针本身可以被修改)

    //const int *p可以指向const int int,但都不可以通过*p赋值

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int num = 520;

    const int cnum = 820;

    const int *p = &cnum;

    printf("%d %d ", &cnum, cnum);

    printf("%d %d ", p, *p);

    p = &num;

    //*p=1024; 此条无法通过编译,*p read-only

    num = 1024;

    return 0;

    }

    //常量指针 (指针本身不可以被修改)

    //int * const p定义了指向之后,无法指向其他量

    //指向非常量的常量指针:指向的值可以被修改

    //指向常量的常量指针:指向的值不可以被修改

    //cmd下无法被编译,unixcodeblocks可以编译

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int num = 520;

    const int cnum = 820;

    int *const p =&cnum;

    *p = 1024;

    printf("%d ", *p );

    //p=&cnum; 常量指针指向num后,不可以修改指向

    return 0;

    }

    //指向"指向常量的常量指针"的指针

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int num = 520;

    const int cnum = 820;

    const int *const p = &cnum;//定义一个指向常量的常量指针

    const int *const *pp = &p;//定义一个指向"指向常量的常量指针"的指针

    printf("%p %p ", pp, &p);//打印p的地址,pp&p相同

    printf("%p %p %p ", *pp, p, &cnum);//打印num的地址,*ppp&num相同

    printf("%d %d %d ", **pp, *p, cnum);//打印三者的值,820

    return 0;

    }

       

    //参数指针

    语法:double atof(char *);

    /* atof的参数时一个指向char类型的指针*/

       

    //void指针

    将任意类型的指针可以转换成为void指针;

    但是void指针转化为其他类型需要使用强制转换;

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int num = 1234;

    int *pi = &num;

    char *ps = "abcd";

    void *pv;

    pv = pi; //pv变成指向整型的指针;

    printf("%p %p ", pi, pv); //两个指针分别的地址;

    //printf("%d ", *pv);//尝试解引用一个void指针,不知道void类型的宽度,编译器无法直接完成

    printf("%d ", *(int *)pv); //pv强制转换成为int类型的指针,并解引用

    pv = ps;

    printf("%p %p ", ps, pv);

    //printf("%s ", pv);//字符串只需要指向首字符的地址就可以了,但是这样写是不规范的

    printf("%s ",(char *)pv);

    return 0;

    }

       

    //NULL指针 //空指针,#define NULL ((void *)0) 指针指向0

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int *p1; //p1成为迷途指针,悬空指针,即没有指定的指针

    int *p2 = NULL;

    printf("%p %p ", p1, p2);//p1地址随机,p2地址 00000000

    printf("%d %d ", *p1, *p2); //unix下编译得到 *p1的值是随机的,*p2返回segmentation fault,因为对NULL指针解引用是非法的,程序崩溃报错

    return 0;

    }

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    指针运算

    // *ip自增

    语法:

    1. *ip += 1;
    2. ++*ip;
    3. (*ip)++;

    //指针间赋值

    语法: iq = ip;

    /* 如果iq和ip同样是指向整型的指针,则将ip中的值copy到iq中,iq也将指向ip所指向的对象 */

       

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    指针传递

    语法:

    swap(a,b);

    void swap(int *p,int *q)

    特点:

    1. 调用方法传参,仅改变指针p的地址 &p ;
    2. *p=12赋值,仅改变内存块的值 *p ;
    3. p=&a指向变量a,仅改变内存块位置 p ;
    4. 调用方法结束,p的地址和内存块都不变,但如果在调用过程中内存块被修改,则值改变 ;

    举例:

    #include <stdio.h>

    void pointer(int *p)

    {

    printf(" the p is %p , addr is %d, *p is %d", p , &p, *p);

    //Line 2 指针p传入方法pointer中:在新的方法中生成了一个p的拷贝p1,新的地址 6356752,但值和指向的内存块数据没变

    *p = 12;

    printf(" the p is %p , addr is %d, *p is %d", p , &p, *p);

    //Line 3 p1改变了其所指向的内存块的值为12,内存块 00F0FF2C 的值变成了22

    int a = 11;

    p = &a;

    printf(" the p is %p , addr is %d, *p is %d", p , &p, *p);

    //Line 4 p1的值指向a,即p1指向a 内存块 0060FEFC,此时p1p分别指向不同的内存块了,不会互相影响

    }

    int main()

    {

    int b = 22;

    int *p = &b;

    printf(" the p is %p , addr is %d, *p is %d", p , &p, *p);

    //Line 1 *p指向b的地址:获得了p(内存块数据)&p(地址)*p(值)

    pointer(p);

    printf(" the p is %p , addr is %d, *p is %d", p , &p, *p);

    //Line 5 方法结束,调用方法结束后,p地址仍是调用前的地址,地址和值没变(改变的仅仅是p的拷贝p1),但是p所指向的内存块数据被p1所改变了,故*p12

    }

    输出:

       

    其他传递方式(来源参考他人)

    1. 传值方式 //和函数的值传递不是一个概念

      语法:

      swap(&a , &b);

      void swap(int *a , int *b)

      // 传入的是变量a的地址 &a,函数接收到的是传入地址的值

      // 使用指针方式修改指向内存块的值,传入的是 a、b变量地址的拷贝。

      注意:函数的值传递的方式是

      swap(a , b);

      void swap(int a , int b)

         

    2. 传引用方式

      语法:

      swap(a,b);

      void swap(int &p,int &q)

      // 使用引用方式,传入的是变量a、b,而不是拷贝,地址不变。

       

    举例:

    #include <stdio.h>

    void swap(int *a , int *b)

    //方法一:传值方式

    {

    printf(" /*** Method 1 ***/");

    printf(" &a addr : %d , &b addr: %d", &a, &b);

    printf(" a memory : %d , b memory: %d", a, b);

    printf(" *a : %d , *b : %d", *a, *b);

    int temp = *a;

    *a = *b;

    *b = temp;

    }

    void swap(int &a , int &b)

    //方法二:传引用方式

    {

    printf(" /*** Method 2 ***/");

    printf(" &a addr : %d , &b addr: %d", &a , &b);

    int temp = a;

    a = b;

    b = temp;

    }

    int main(int argc, char const *argv[])

    {

    int a = 3 , b = 5;

    printf(" &a addr : %d , &b addr: %d", &a , &b);

    printf(" a : %d , b : %d", a , b);

    swap(&a , &b); //方法一

    printf(" &a addr : %d , &b addr: %d", &a, &b);

    printf(" a : %d , b : %d", a , b);

    swap(a , b); //方法二

    printf(" a : %d , b : %d ", a , b);

    return 0;

    }

    输出:

       

    ————————————————————————————————————————————

    数组指针和指针数组

    注意:赋值符号"="号两边的数据类型必须是相同的,通过这点可以排除在写数组与指针时的错误;

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    数组指针 //指向数组的指针

    注意:不同的数据类型占的地址数(字节)不同,char:1,int:4,float:4,double:8

    定义:

    //一维

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    //intchar同理

    int temp[5] = {1, 2, 3, 4, 5};

    int (*p)[5] = &temp;//指针p指向temp数组的首地址

    int i;

    for (i = 0; i < 5; ++i)

    {

    printf("%d ", *(*p + i));

    //*p指向temp数组的首地址,*p+i代表后移几个字节的地址,*(*p+i)代表指向地址的值

    }

    return 0;

    }

    //二维,行指针

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int array[4][5] = {{1, 2, 3, 4, 5}, {11, 12, 13, 14, 15}, {21, 22, 23, 24, 25}, {31, 32, 33, 34, 35}, {41, 42, 43, 44, 45}};

    int (*p)[5];//该语句是定义一个数组指针,指向含4个元素的一维数组。或直接写成 int (*p)[5] = array;

    p = array;//将该二维数组的首地址赋给p,也就是a[0]&a[0][0]

    //在这里,数组指针p共有三个int指针,赋值时意味着将p的三个指针指向 array第一行的三个元素;

    for (int i = 0; i < 4; ++i)

    {

    for (int j = 0; j < 5; ++j)

    {

    printf("%2d ", *(*(p + i) + j));

    }

    printf(" ");

    }

       

    return 0;

    }

    另一种表达方式:

    ...

    int (*p)[4][5]=&array;

    ...

    printf("%2d ", *(*(*p + i) + j));

    ...

    //都表示数组中ij列一个元素

    *(p+i) == p[i]

    *(*(p+i)+j) == p[i][j] == *(p[i]+j) == (*(p+i))[j]

    *(*(*(p+i)+j)) == p[i][j][k]

       

    p++;//该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

       

       

    大小:在32位系统下永远是4字节

    1

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    int a[10];

    int *p, i;

    for (i = 0; i < 10; ++i)

    {

    scanf("%d", &a[i]);

    }

    for (p = &a[0]; p < (a + 10); p++)

    //p+i = a+i = &a[i] 这三者意思相同,所以循环结构使用 p < (a + 10),等价于 i < 10

    {

    printf("%d ", *p);

    }

    return 0;

    }

    2

    #include <stdio.h>

    int main()

    {

    //数组指针的大小必须与数组相同,否则编译不通过,此处均为[5]

    char a[5] = {'a', 'b', 'c', 'd'};

    //p1 p2 都是数组指针,指向的是整个数组

    //&a 是整个数组的首地址,a是数组首元素的首地址

    char (*p1)[5] = &a;

    //p1指向&a是对的,左右都是整个数组的首地址

    char (*p2)[5] = a;

    //p2指向a,编译时会出现warming,但是"="两边的数据类型不一致,左边的是指向整个数组的指针,右边的数据类型是指向单个字符的指针。

    char (*p3)[5] = (char (*)[5])a;

    //p2类型如果要正常使用的话则使用p3这种强制转换,右边强制转换成为a整个数组的首地址

    printf("a=%d ", a);

    printf("a=%c ", a[0]);

    printf("&a=%d ", &a);

    printf("p1=%c ", **p1);

    printf("p2=%c ", **p2);

    printf("p3=%c ", **p3);

    printf("p1+1=%c ", **(p1 + 1));

    printf("p2+1=%c ", **(p2 + 1));

    printf("p3+1=%c ", **(p3 + 1));

    return 0;

    }

    输出:

    出现的warming信息为p2导致,左右类型不一致

       

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    指针数组 //用于存储指针的数组

    定义:

    //一维

    #include <stdio.h>

    int main(int argc, char const *argv[])

    {

    //int

    int a = 1;

    int b = 2;

    int c = 3;

    int d = 4;

    int e = 5;

    int *p[5] = {&a, &b, &c, &d, &e};//数组里面每一个元素都指向abcde的地址

    for (int i = 0; i < 5; ++i)

    {

    printf("%d ", *p[i]);//循环打印每一个指针对应地址的值 *

    }

    //char

    char *q[5] = {"aaa", "bbb", "ccc", "ddd", "eee"};

    for (int j = 0; j < 5; ++j)

    {

    printf("%c ", *q[j]); //*表示取出的是字符

       

    }

    for (int k = 0; k < 5; ++k)

    {

    printf(" %s", q[k]);//不加*表示字符串

    }

    return 0;

    }

       

    //二维

    int *p[3]; //定义的p数组中的三个元素都是int指针,分别是p[0]p[1]p[2],所以要分别赋值。

    int a[3][4];

    p++; //该语句表示p数组指向下一个数组元素。注:此数组每一个元素都是一个指针

    for(i=0;i<3;i++)

    p[i]=a[i];

       

    //都表示数组中ij列一个元素

    *(p+i) == p[i]

    *(*(p+i)+j) == p[i][j] == *(p[i]+j) == (*(p+i))[j]

    *(*(*(p+i)+j)) == p[i][j][k]

    赋值:*p=a; //这里*p表示指针数组第一个元素的值,a的首地址的值。

    大小:数组的大小由数组本身来决定,32位系统下每个指针占4字节,大小不确定;

    举例:

    #include <stdio.h>

    int main()

    {

    int i;

    char c1[] = "How";

    char c2[] = "are";

    char *c3 = "you"; //该指针变量指向字符串所在字符数组的首地址。

    char *pArray[3]; //该数组元素可以指向char类型或数组类型

    pArray[0] = c1; //指针变量pArray[0]指向了c1的首地址

    pArray[1] = c2;

    pArray[2] = c3;

    for(i = 0; i < 3; i++)

    printf("%s ", pArray[i]); //printf("%s ", pArray[0])等价于printf("%s ", c1)

    return 0;

    }

    输出:

       

       

    出处: http://www.cnblogs.com/hongcha717/archive/2010/10/24/1859780.html

    出处: http://www.cnblogs.com/mq0036/p/3382732.html

    ————————————————————————————————————————————

    结构体

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    编译器会将结构体的数据进行内存对其,如果定义 char a;int b;char c;

    对其前:6个字节

    a

    b

    b

    b

    b

    c

    对其后:12个字节

    a

      

      

      

    b

    b

    b

    b

    c

      

      

      

    如果定义的是 char a;char c;int b;

    则调整为

    a

    c

      

      

    b

    b

    b

    b

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    定义

    #include <stdio.h>

    //第一种定义方法

    struct Book //定义结构体名

    {

    char title[128];

    char author[40];

    float price;

    unsigned int date;//无符号整型

    char publisher[40];

    } book;//book是结构体变量名

    //第二种定义方法

    struct Book2

    {

    float price2;

    unsigned int date2;

    } book2;

    //第三种定义方法

    struct Book3

    {

    int number;

    int number2;

    } book3 = {1, 2};

    //结构体嵌套

    struct Data

    {

    int year;

    int month;

    int day;

    };

    struct Nested

    {

    struct Data data;

    char a;

    } nested =

    {

    {2017, 4, 17},

    'i'

    };

    int main(void)

    {

    //第一种初始化方法

    struct Book book =//初始化结构体

    {

    "aaa",

    "bbb",

    12.0,

    20170417,

    "ccc"

    };

    //第二种初始化方法

    struct Book2 book2 =//通过这种写法只初始化某一个变量

    {

    .price2 = 48.0

    };

       

    //scanf("%s",book.title);

    //scanf("%s",book.author);

    //...

    printf("%s ", book.title);

    printf("%s ", book.author);

    printf("%f ", book.price);

    printf("%d ", book.date);

    printf("%s ", book.publisher);

    printf("- - - - - - - - ");

    printf("%f ", book2.price2);

    //...

    printf("- - - - - - - - ");

    //结构体嵌套打印

    printf("%d %d %d ", nested.data.year, nested.data.month, nested.data.day);

    return 0;

    }

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    结构体数组

    #include <stdio.h>

    //第一种定义方法

    struct Way1

    {

    char a;

    char b;

    int c;

    } way1 [3];

    //第二种定义方法

    struct Way2

    {

    char d;

    char e;

    int f;

    };

    struct Way2 way2 [10];

    int main(int argc, char const *argv[])

    {

    //初始化结构体数组

    struct Way1 way1[3] =

    {

    {'a', 'b', 0},

    {'c', 'd', 1},

    {'e', 'f', 2}

    }

    return 0;

    }

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    结构体指针

    #include <stdio.h>

    struct Book

    {

    char title[128];

    char author[40];

    float price;

    unsigned int date;

    char publisher[40];

    } book =

    {

    "aaa",

    "bbb",

    12.0,

    20170417,

    "ccc"

    };

    int main(void)

    {

    struct Book *pt;

    pt = & book;//结构体的变量名并不是指向结构体的地址,定义结构体指针时必须使用 &

    //第一种方法

    printf("%s ", (*pt).title);

    printf("%s ", (*pt).author);

    printf("%f ", (*pt).price);

    printf("%d ", (*pt).date);

    printf("%s ", (*pt).publisher);

    printf("- - - - - - - - - - - ");

    //第二种方法

    printf("%s ", pt->title);

    printf("%s ", pt->author);

    printf("%f ", pt->price);

    printf("%d ", pt->date);

    printf("%s ", pt->publisher);

    return 0;

    }

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    传递结构体变量

    #include <stdio.h>

    struct Date

    {

    int year;

    int month;

    int day;

    };

    struct Book

    {

    char title[128];

    float price;

    struct Date date;

    };

    struct Book getInput(struct Book book);

    struct Book getInput(struct Book book)

    {

    printf("input the title:");

    scanf("%s", book.title);

    printf("input the price:");

    scanf("%f", &book.price);

    printf("input the date:");

    scanf("%d %d %d", &book.date.year, &book.date.month, &book.date.day);

    return book;

    }

    struct Book printBook(struct Book book);

    struct Book printBook(struct Book book)

    {

    printf("%s ", book.title);

    printf("%f ", book.price);

    printf("%d-%d-%d", book.date.year, book.date.month, book.date.day);

    }

       

    int main()

    {

    struct Book b1, b2;

    printf("input the first info ");

    b1 = getInput(b1);

    printBook(b1);

    return 0;

    }

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    传递指向结构体变量的指针 //基本结构同上

    #include <stdio.h>

    struct Date

    {

    int year;

    int month;

    int day;

    };

    struct Book

    {

    char title[128];

    float price;

    struct Date date;

    };

    void getInput(struct Book *book);

    void getInput(struct Book *book)//不需要返回值,直接定义成为void即可

    {

    printf("input the title:");

    scanf("%s", book->title);

    printf("input the price:");

    scanf("%f", &book->price);

    printf("input the date:");

    scanf("%d %d %d", &book->date.year, &book->date.month, &book->date.day);

    }

    void printBook(struct Book *book);

    void printBook(struct Book *book)

    {

    printf("%s ", book->title);

    printf("%f ", book->price);

    printf("%d-%d-%d", book->date.year, book->date.month, book->date.day);

    //void类型没有返回值 return

    }

       

    int main(void)

    {

    struct Book b1, b2;

    printf("input the first info ");

    getInput(&b1);//调用时直接取地址

    printBook(&b1);

    return 0;

    }

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    动态申请结构体

    //使用malloc函数为结构体分配存储空间,free函数释放

    #include <stdio.h>

    #include <stdlib.h>

    struct Date

    {

    int year;

    int month;

    int day;

    };

    struct Book

    {

    char title[128];

    float price;

    struct Date date;

    };

    void getInput(struct Book *book);

    void getInput(struct Book *book)//不需要返回值,直接定义成为void即可

    {

    printf("input the title:");

    scanf("%s", book->title);

    printf("input the price:");

    scanf("%f", &book->price);

    printf("input the date:");

    scanf("%d %d %d", &book->date.year, &book->date.month, &book->date.day);

    }

    void printBook(struct Book *book);

    void printBook(struct Book *book)

    {

    printf("%s ", book->title);

    printf("%f ", book->price);

    printf("%d-%d-%d", book->date.year, book->date.month, book->date.day);

    }

       

    int main(void)

    {

    struct Book *b1, *b2;

    b1 = (struct Book *)malloc(sizeof(struct Book));

    if (b1 == NULL)

    {

    printf("内存分配失败 ");

    exit(1);

    }

       

    printf("input the first info ");

    getInput(b1);//因为b1是指针,所以不需要取地址操作符

    printBook(b1);

    free(b1);

    return 0;

    }

       

    ————————————————————————————————————————————

    预处理器

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    文件包含 #include "文件名" 或 #include <文件名>

    1. 用" "引起来,则在源文件所在的位置查找该文件;
    2. 如果在该位置没有找到文件或用< >括起来的,则根据相应的规则查找该文件,这个规则同具体的实现有关

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    两个预处理语句 #ifdef 和 #ifndef

    用法:

    #ifndef HDR

    #define HDR

    /* hdr.h文件的内容在这里*/

    #endif

       

    /* 用来测试某个名字是否已经定义,等价于 */

    #if !defined(HDR)

    #define HDR

    #endif

    举例:

    /* 测试SYSTEM变量后确定包含某个文件 */

    #if SYSTEM == SYSV

    #define HDR "sysv.h"

    #elif SYSTEM == BSD

    #define HDR "bsd.h"

    #elif SYSTEM == MSDOS

    #define HDR "msdos.h"

    #else

    #define HDR "default.h"

    #endif

    #include HDR

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    宏替换

    1. #define 名字替换文本

      用法:较长的替换文本可以在待续的行末尾加上反斜杠符

      举例:

      1. 例:#define forever for(;;)

        /* 该句为无限循环定义了一个新名字forever */

      2. 例:#define max(A,B) ((A)>(B)?(A):(B))

        /* 形参A和B每次出现都将被替换成对应的实际参数,不过要适当使用括号来规范计算次序的正确性 */

      3. 例:#define dprint(expr) printf(#expr " = %g ",expr)

        /* 当使用时dprintf(x/y);时被扩展为 printf("x/y" "= %g ",x/y); */

      4. 例:#define paste(front,back) front ## back

        /*预处理器运算符## 为宏定义提供了连接实际参数的手段*/

        /* 在调用paste(name,1)时,将建立记好 name1*/

    2. #undef getchar

      int getchar(void){...}

      用法:通过#undef 取消名字的宏定义,这样可以保证后续的调用是函数调用,而不是宏调用

    ————————————————————————————————————————————

    getchar /putchar 输入输出

    语法:

    c = getchar(); // 获取控制台输入

    putchar(c); //输出

    ————————————————————————————————————————————

    EOF,End Of File,文件尾标志。 从数值上来看,就是整数-1

    linux:在输入回车换行后的空行位置,按 ctrl+d (先按ctrl键,不放,再按d键)

    windows:在输入回车换行后的空行位置,按 ctrl+z,再回车确认

    ————————————————————————————————————————————

       

  • 相关阅读:
    iostream、printf/wprintf和中文输出【转】
    java命令行运行错误:ClassNotFoundException【转】
    一致性代码段和非一致性代码段【转】
    Winform disign tips(转)
    WinForm下多层架构的实现(转)
    如何在GPU上产生随机数
    最快速度找到内存泄漏
    给定单链表的头结点,如何快速的找到倒数的第n个节点?
    DX11_基于GPU_GeometryShader的3D精确拾取
    Directx11:基于GPU_GeometryShader的Billboard公告板绘制
  • 原文地址:https://www.cnblogs.com/hughdong/p/6727919.html
Copyright © 2011-2022 走看看