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 = '\b', TAB = '\t', NEWLINE = 'n', VTAB = '\v', RETURN = '\r'};

    /*

    BELL = '\a',

    BACKSPACE = '\b',

    TAB = '\t',

    NEWLINE = 'n',

    VTAB = '\v',

    RETURN = '\r'

    */

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

关键字

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

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\n",*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\n", *p, *(p + 1)); //打印首地址的值与第二个地址的值

   

//int

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

int *q;

q = a;

//或写成 int *q = a;

printf("%d %d\n", *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\n", *p);

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

{

printf("%s\n", *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\n", &cnum, cnum);

printf("%d %d\n", 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\n", *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\n", pp, &p);//打印p的地址,pp&p相同

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

printf("%d %d %d\n", **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\n", pi, pv); //两个指针分别的地址;

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

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

pv = ps;

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

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

printf("%s\n",(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\n", p1, p2);//p1地址随机,p2地址 00000000

printf("%d %d\n", *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("\nthe p is %p , addr is %d, *p is %d", p , &p, *p);

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

*p = 12;

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

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

int a = 11;

p = &a;

printf("\nthe 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("\nthe p is %p , addr is %d, *p is %d", p , &p, *p);

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

pointer(p);

printf("\nthe 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("\n\n /*** Method 1 ***/");

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

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

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

int temp = *a;

*a = *b;

*b = temp;

}

void swap(int &a , int &b)

//方法二:传引用方式

{

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

printf("\n &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("\n a : %d , b : %d", a , b);

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

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

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

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

printf("\n a : %d , b : %d\n", 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("\n");

}

   

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\n", a);

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

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

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

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

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

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

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

printf("p3+1=%c\n", **(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("\n%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\n", book.title);

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

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

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

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

printf("- - - - - - - - \n");

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

//...

printf("- - - - - - - - \n");

//结构体嵌套打印

printf("%d %d %d\n", 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\n", (*pt).title);

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

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

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

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

printf("- - - - - - - - - - -\n");

//第二种方法

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

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

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

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

printf("%s\n", 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\n", book.title);

printf("%f\n", 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\n");

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\n", book->title);

printf("%f\n", 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\n");

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\n", book->title);

printf("%f\n", 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("内存分配失败\n");

exit(1);

}

   

printf("input the first info\n");

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\n",expr)

      /* 当使用时dprintf(x/y);时被扩展为 printf("x/y" "= %g\n",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,再回车确认

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

   

posted @ 2017-04-18 15:09  hugh.dong  阅读(985)  评论(0编辑  收藏  举报