码迷,mamicode.com
首页 > 编程语言 > 详细

C语言从入门到精通,看这一篇就够了

时间:2018-11-16 20:45:53      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:产生   字母   静态变量   strcpy   编译器   寄存器变量   内存分配   控制   tps   

No.1 计算机与程序设计语言的关系

计算机系统由硬件系统和软件系统构成,硬件相当于人类的肉体,而软件相当于人类的灵魂,如果脱离了灵魂,人类就是一具行尸走肉

No.2 C语言的特点

  • 代码简洁,灵活性高
  • 语言简单易懂
  • 生成目标代码质量高,效率高
  • 允许直接访问物理地址,操作硬件
  • 可移植性较好
  • 数据的封装,在安全性上存在很大缺陷
  • 对于字符串处理,只能通过自负数组实现,绘图操作复杂
  • 类型检查机制较弱,缺乏支持代码重用的语言结构

No.3 国际惯例HelloWorld

#include <stdio.h>  
int main()  
{  
    printf("Hello World!\n");  
    return 0;  
} 

No.4 C程序的编译与运行

当我们在编译器上将代码写好,此时的文件是.c文件,该文件是C语言程序源代码的扩展名,此时的程序叫源程序,当程序通过编译器进行编译时,此时会产生一个目标程序.obj,将目标程序和库文件连接成机器码文件,就是exe可执行程序

No.5 配置Clion

  • Clion安装,直接点点点
  • 破解方法,传送门
  • 安装Cygwin

    • 下载Cywin,传送门
    • 点点点,直到direct connection,添加网易镜像源<http://mirrors.163.com/cygwin/>;
    • 选择安装的模块,依次搜索 gcc-core、gcc-g++、make、gdb、binutils,选择devel文件夹,点击前面的skip,将skip切换成版本号
    • 继续奠奠奠
  • 配置Cygwin,打开Clion,选择File->Setting->Build, Execution, Deployment->Toolchains

No.5 基本字符集

标识符

什么是标识符 ?

在C语言中,变量名、常量名、关键字、函数名、方法名都属于标识符

标识符如何命名?

  • 只能有字母、数字、下划线组成,且数字不能打头
  • 严格区分大小写,变量和函数一般都是小写字母命名

关键字

什么是关键字?

C语言中具有特殊含义的英文单词,通常用于构成语句,存储结构、定义数据类型等

关键字有哪些?

  • 基本数据类型
    • char 声明字符串类型
    • iint 声明整型类型
    • float 声明浮点型
    • double 声明双精度浮点型
    • void 空类型
  • 类型修饰
    • short 声明短类型
    • llong 声明长类型
    • signed 声明有符号型
    • unsigned 声明无符号型
  • 其他数据类型
    • enum 声明枚举类型
    • struct 声明结构体
    • union 声明共用体
  • 流程控制
    • 条件判断 if/else/switch/case/default/goto
    • 循环 while/do/for/break/continue
    • 返回 return
  • 存储类型
    • auto 自动变量
    • static 静态类型
    • register 寄存器变量
    • extern 外部变量
  • 其他
    • sizeof 查看类型长度
    • typedef 声明类型别名
    • const 指定变量不能被当前线程修改
    • volattile 强制编译器每次从内存中读取该变量的值

分隔符

  • ; 语句结尾
  • {} 函数体
  • () 函数定义时用来包含参数,还可以用来修改运算顺序
  • [] 定义数组类型
  • . 结构体引用成员
  • , 参数分割
  • // 单行注释
  • /**/ 多行注释

No.6 数据类型

  • 整型 用于准确地表示整数,根据表示范围的不同分为以下三种: 短整型(short) < 整型(int) < 长整型(long)

  • 浮点型 用于标识实数(小数)根据范围和精度不同分为以下两种: 单精度浮点数(float) < 双精度浮点数(double)

  • 字符型 用来描述单个字符,char除了上面三种以外,还可以使用long、short、signed、unsigned来修饰不同的数据类型

数据类型的转换

  • 强制类型转换 (类型关键字)(表达式)

    • 例如(int)5.2/2,首先将5.2转换成5,然后再用5/2,结果是2
  • 自动类型转换
    • 不同数据类型的变量混合运算时,会自动升级成数据类型最大的那个,所有浮点运算都是以double进行运算的,即使最大的数据类型仅仅是float
    • 赋值时,右侧表达式的值转换为左边变量的类型

No.7 常量与变量

常量

  • 整型常量
    • 十进制常量,正负号开头,后面跟0-9中的数字,正号可以省略
    • 八进制,正负号开头,后面跟0-7中的数字,正号可以省略
    • 十六进制,正负号开头,接着是0x,后面跟0-9中的数字或a-f,其中a-f分别表示10-15,正号可以省略
    • 除上述情况外,还可以在常量屁股后面加L或U,L表示长整型,U表示无符号型
  • 实型常量
    • 十进制小数,由0-9和小数点组成
    • 十进制指数,由0-9、小数点和e组成
  • 字符常量

    • 用单引号括起来的一个普通字符或转义字符
    • 字符常量在存储时,保存的是该字符对应的ASCII码
  • 字符串常量
    • 用一对双引号括起来的或者多个字符构成的字符串序列
    • 系统会在存储字符串的时候自动加上\0,表示字符串结束的标志
  • 符号常量
    • 又叫宏常量,是一个预处理命令:#define 常量名 常量值
    • 定义后,程序中所有出现这个标识符的地方都会用该常量值替换

变量

什么是变量?

程序在运行过程中,它的值可以随着程序的运行不断的动态修改,变量代表的内存的一个空间,而变量名的作用是可以通过变量名找到这个变量名对应的那个变量的空间

定义变量到底做了什么?

int a = 123,首先在内存中开辟了4个字节的内存空间,并且并这个内存空间起了一个名字,叫做a,后面的= 123,这一步完成的操作是变量的初始化,通过a这个变量,就那个内存空间存储了123这个数据

No.8 运算符与表达式

  • 算术运算符

    • +、-、*、/、%分别表示加、减、乘、除、取余

    • 除号前后都是整数,结果才是整数,否则,结果是小数,取余运算要求前后都是整数
#include <stdio.h>

int main() {
    int num;
    printf("请输入一个5位数:");
    scanf("%d",&num);
    printf("倒叙输出:\n");
    for (int i = 0; i < 5; i++) {
        printf("%d",num % 10);
        num /= 10;
    }
    printf("\n");
    return 0;
}
  • 关系运算符

    • <、<=、>、>=、==、!=分别表示小于、小于等于、大于、大于等于、等于和不等于
    • 关系表达式运行的结果是一个逻辑值,即0或1
#include <stdio.h>

int main() {
    int a = 1,b = 2,c = 3;
    int x,y;
    x = a + b == c; // x = 1
    y = 11 >b != a; // y = 0
    printf("x = %d,y = %d\n",x,y);
    return 0;
}
  • 逻辑运算符

    • !、&&、||分别是逻辑非、逻辑与、逻辑或
    • &&前面的表达式为假,就不会运行第二个表达式,||前面的表达式为真,就不会运行第二个表达式
#include <stdio.h>

int main() {
    int year;
    printf("请输入年份:");
    scanf("%d",&year);
    if ((!(year % 100) && !(year % 400))||year % 4 == 0){
        printf("%d年是闰年",year);
    }
    else{
        printf("%d年是平年",year);
    }
    return 0;
}
  • 赋值运算符

    • +=、-=、*=、/=、%=、=分别是加等、减等、乘等、除等、模等、等于
  • 条件表达式

    • a?b:c
    • a为true,执行b,反之,执行c
#include <stdio.h>

int main() {
    int a = 1;
    int b = 2;
    int c = 3;
    int max = 0;
    max = a>b?(a>c?a:c):(b>c?b:c);
    printf("max=%d",max);
    return 0;
}
  • 逗号表达式

    • 从左到右依次执行每个表达式
    • 赋值的话取最右边表达式的值
#include <stdio.h>

int main() {
    int a = 1;
    int b = 2;
    int c = 3;
    c = (a = 10,b = 10,2 * a + 5,a + a * b + c);
    printf("a = %d, b = %d, c = %d\n",a,b,c); // a = 10, b = 10, c = 113
    return 0;
}
  • 长度测试运算符

    • sizeof 通常用来测试某个数据类型占用的内存空间大小
#include <stdio.h>

int main() {
    int a = 1;
    float b = 2.0;
    char c = ‘3‘;
    printf("%d %d %d\n", sizeof(a), sizeof(b), sizeof(c)); // 4 4 2
    return 0;
}
  • 运算符的优先级

    • () > ! > 算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符

No.9 输入与输出

  • 字符输入、输出函数
    • getchar() 例如,str = getchar();
    • putchar() 例如,putchar(str);
  • 格式化输入、输出函数
    • scanf() 例如,scanf("%c",&str);
    • printf() 例如,printf("%c",str);

No.10 基本程序结构

  • 顺序结构与判断结构if的使用

    技术分享图片

  • 判断结构switch的用法

    技术分享图片

  • 循环结构

    技术分享图片

  • 流程跳转控制语句
    • break 只能用来循环和switch中,跳出switch或跳出循环,在多层循环中,只能跳出一层循环
    • continue 跳出循环体中该语句下面的业务逻辑,继续执行下一次循环

No.11 数组

一维数组与二维数组

什么是数组?

将数据类型一致的多个变量存放在一块连续的的内存空间中,元素按照索引的方式连续存放、访问

一维数组

  • 数组定义 数据类型 数组名 [数组长度],例如 int num[10];

  • 初始化

    • int num[] = {1,2,3,4,5}; 所有元素都赋值过了,所以不需要指定数组长度
    • int num[5] = {1, 2 , 3}; 赋值了部分元素,没有赋值的系统会被初始化为0

    • int num[]; 全部初始化为0
  • 引用 数组下标都是从0开始的

二维数组

  • 数组定义 数据类型 数组名 [数组长度][数组长度],例如 int nums[10][10];
  • 初始化

    • 连续赋值 int[2][2] = {1,2,3,4};
    • 分段赋值 int[2][2] = {{1,2},{3,4}}
    • 部分赋值 int[2][2] = {{1,2},{3}}
    • 全部不赋值 int[2][2] = {};系统全部赋值为0
    • 如果全部元素都赋值了,可以省略第一维的长度
  • 引用 和一维数组类似

冒泡排序

#include <stdio.h>

int main() {
    int nums[10];
    // 随机为数组赋值
    for (int i = 0; i < 10; ++i) {
        nums[i] = rand()%100+1;
    }
    printf("原数组: \n");
    // 编译原数组
    for (int i = 0; i < 10; ++i) {
        printf("%d ",nums[i]);
    }
    // 冒泡排序
    for (int i = 0; i < 10; ++i) {
        for (int j = 0; j < i; ++j) {
            if(nums[j]>nums[j+1]){
                int temp = nums[j];
                nums[j] = nums[j+1];
                nums[j+1] = temp;
            }
        }
    }
    printf("\n");
    printf("新数组: \n");
    for (int i = 0; i < 10; ++i) {
        printf("%d ",nums[i]);
    }
    return 0;
}

字符串与字符数组

前面我们学习了数组的定义,假如我需要存储一个名字,就需要char[5] = {‘k‘, ‘e‘, ‘r‘, ‘n‘, ‘e‘, ‘l‘},但是这样当我们需要使用名字的时候就需要遍历整个数组,于是,我们可以把它当作一个整体来保存,这就是字符串

初始化

  • char name[7] = "kernel";

  • char name[7] = {"kernel"};

  • 可以不指定数组长度,数组的长度必须比有效字符个数多一个,用于存储\0,字符串结束标志

输入输出函数

  • scanf() 例如 scanf("%s",name);

  • gets() 例如 gets(name);

  • printf() 例如 printf("%s",name);

  • puts() 例如 puts(name);

复制

#include <stdio.h>
#include <string.h>

int main() {
    char name[7] = {"kernel"};
    char names[7];
    strcpy(names, name);
    puts(names);
    return 0;
}

拼接

#include <stdio.h>
#include <string.h>

int main() {
    char str[10] = {"hello"};
    strcat(str, "-world");
    puts(str);
}

比较

#include <stdio.h>
#include <string.h>

int main() {
    char name[7] = "kernel";
    char names[7] = "kernel";
    // strcmp函数,从左到右根据ASCII码进行比较,知道遇到不同的字符为止
    // 相同返回0,第一个变量 > 第二个变量,返回一个比0大的数,否则,返回一个比0小的数
    // 直接使用==比较的是两个变量的内存地址
    printf("%d",strcmp(name,names));
    printf("%d",name == names);
    return 0;
}

长度

#include <stdio.h>
#include <string.h>

int main() {
    char name[] = "kernel";
    printf("字符串的长度=%d",strlen(name));
    return 0;
}

No.12 函数

函数是什么?

C语言作为结构化的程序设计语言,模块化是一种重要的设计思想,在模块化设计中,我们通常将复杂的任务分割成若干模块的组合,让每个模块实现一定的功能,我们将这些模块成为函数,使用函数可以提高代码的可读性和复用性

函数的声明

当我们想调用自定义函数时,我们需要让系统知道存在这么一个函数,所以我们需要对函数进行声明,将自定义函数写在main函数之前的不用进行声明,写在main函数后面的函数需要进行声明

函数的定义

  • 函数类型

    • 无返回值 void
    • 有返回值根据返回值的类型确定函数类型
  • 函数名

    • 遵循小驼峰命名法,见名知意
  • 形参与实参

    • 实参 实参是调用函数时传入的参数
    • 形参 形参是函数定义的时候使用的,形参定义时需指定类型,但是只有在被调用时才分配内存单元,只有在该函数中可以正常调用,其他地方会报错
  • 函数体

    • 函数的主体结构
  • 返回值
    • 函数的返回值需要跟函数类型保持一致,只能返回一个值,给程序提供一个出口

函数的使用

# 函数的声明
int sum(int, int);
# 函数体
int sum(int x, int y){
    return x + y;
}
# 函数的使用
int result = sum(10, 20);

函数的传值与传址

传值是单向传递,形参的改变并不影响实参,实参和形参各自占用一段内存空间

传址是将实参的地址作为值传递给形参,实参与形参指向同一块内存空间,所以形参的改变会影响实参,在C语言中通过传址传递数据的一般是数据和指针,但是操作大批量数据时,会影响性能

函数的递归和嵌套

  • 嵌套 在一个函数中调用其他的函数,但是不可以调用mian函数
  • 递归 在该函数中不仅可以调用其他的函数,还可以调用自己,这种方式成为递归
    • 直接递归 函数中直接调用自己
    • 间接递归 函数中调用其他函数,其他函数又调用该函数
#include <stdio.h>
#include <stdlib.h>
int main() {
    int box(int);
    int n;
    long num;
    printf("请输入一个整数:\n");
    scanf("%d",&n);
    num = box(n);
    printf("%d的阶乘是:%d\n",n,num);
}
int box(int n){
    if (n < 0){
        printf("输入数据有误");
        exit(0);
    }
    if (n == 0 || n == 1){
        return 1;
    }
    else{
        return n * box(n-1);
    }
}

No.13 指针

访问变量有两种方式

  • 间接访问 通过指针指向变量,先获得变量地址,然后根据地址去访问对应的存储单元
  • 直接访问 通过变量名或地址直接访问

指针的使用

  • 定义 类型说明符号 *变量名
  • 初始化 可以使用&取变量地址 int *p = &a
  • 访问 可以使用*来访问指针指向的变量

指针与一维数组

  • 指向数组元素 用指针指向数组的某个元素 int *p;p = &num[4];

  • 指向数组 用指针指向数组,数组名存储的是该数组的首地址,int *p;p = num;

  • 引用数组元素
    • 访问数组的第2个元素 num[2]
    • 访问数组的第2个元素 *(a+2)
    • 访问数组的第2个元素 *(p+2)

指针与字符串

字符串的定义除了之前提到的字符数组外,还有另外一种方式,现在我们可以使用char *str = "Hello",系统为该字符串分配相应的连续内存空间,将存储空间的首地址赋值给指针变量str

指针与二维数组

二维数组是按行与列存储数据的,可以看成若干行个长度为若干列一维数组,如num[4][2],就可以看成4个长度为2的一维数组,num代表二维数组首元素的地址,即&num[0],我们可以将num[0]看作指向num[0][0]的指针,那么num[0]+1即指向num[0][1],同理num[1]+2就指向num[1][2],通过前面的一维数组,我们知道num[i]等价于(num+i),同样的,扩展到二维数组上面来,num[i][j]与*(num+i)+j、num[i]+j都是等价的,而求num[i][j]的值,用、*(num[i]+j)与、*((num+i)+j)

函数与指针

  • 指针作为函数的形参
#include <stdio.h>

int main(){
    void replace(char *, char);
    char str[] = "how do you do";
    char c = ‘o‘;
    replace(str,c);
    puts(str);
}
void replace(char *s,char c){
    char *p;
    char *q;
    for (p = s; *p && *p != c; p++) {
        q = p;
        while (*p){
            while (*p && *p == c){
                p++;
            }
            while (*p && *p != c){
                *q++ = *p++;
            }
        }
        *q = ‘\0‘;
    }
}
  • 指向函数的指针 函数的首地址一般为函数的指针,如果我们声明一个指针指向函数名,就可以通过这个变量执行函数
#include <stdio.h>

void points(int x, int y, int(*p)()){
    int res;
    res = (*p)(x,y);
    printf("%d",res);
}

int main(){
    int max(int, int);
    int min(int, int);
    int x,y;
    scanf("%d",&x);
    scanf("%d",&y);
    points(x,y,max);
    points(x,y,min);
}

int max(int x, int y){
    if (x > y){
        return x;
    } else{
        return y;
    }
}

int min(int x, int y){
    if (x > y){
        return y;
    } else{
        return x;
    }
}
  • 指针函数 函数的返回值是一个地址的函数成为指针函数
#include <stdio.h>

char *day_name(int n){
    static char name[7][20] = {
            "Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"
    };
    return (n <1 || n>7)?name[0]:name[n];
}

int main(){
    int i;
    printf("请输入一个星期编号:\n");
    scanf("%d",&i);
    printf("编号%d对应的星期为:%s",i,day_name(i));
}

指针数组

保存保存多个字符串的方式有两种

  • 二维数组 char name[4][10] = {"kernel","alex","eric","nino"};
  • 指针数组char *p_name[4] = {"kernel","alex","eric","nino"};

二级指针

二级指针通常用来存储指针数组的地址以及实现指针数组元素的访问

使用方法 int a,*b,**c;b = &b;c = &b;

#include <stdio.h>

int main(){
    int a[5] = {1,2,3,4,5};
    int *b[5];
    int **c;
    for (int i = 0; i < 5; ++i) {
        b[i] = &a[i];
    }
    c = b;
    for (int i = 0; i < 5; ++i, ++c) {
        printf("%d\n",**c);
    }
}
//1
//2
//3
//4
//5

内存的动态分配

内存中存放了什么?

  • 栈 函数调用返回地址,形参,局部变量等程序运行信息

  • 堆 自由存储区域,动态分配申请该空间

  • 静态存储区 存放全局变量与静态变量,编译期就分配号内存了
  • 程序代码存储区 存放正在执行的代码

动态分配函数

  • malloc 分配若干字节的连续内存空间,分配成功返回指向该存储区的首地址,否则返回空指针
  • calloc 分配若干字节的连续内存空间,分配成功返回指向该存储区的首地址,否则返回空指针
  • realloc 将p所指的存储区大小更改为n,如果成功,就不能再通过p使用原来的存储空间,反之,返回空,p依旧指向原来的位置 int *q;q=(int)realloc(p,MAX_SIZE\sizeof(int))
  • free 释放动态申请的空间给系统,由系统再次支配
#include <stdio.h>
#include <stdlib.h>
#define N 10
int main()
{
    int *p = 0;
    int i, num, *q = 0;
    p = (int *) malloc((N * sizeof(int)));
    if (p == 0)
    {
        printf("内存分配错误!\n");
        exit(0);
    }
    printf("请输入要存储的元素个数:\n");
    scanf("%d", &num);
    if (num <= N) {
        for (i = 0; i < num; i++){
            scanf("%d", p + i);
        }
    } else {
        for (i = 0; i < num; i++){
            q = (int *) realloc(p, (N + N) * sizeof(int));
        }
        if (q == 0){
            exit(0);
        }
        for (i = 0; i < num; i++){
            scanf("%d", q + i);
        }
        p = q;
    } for (i = 0; i < num; i++){
        printf("%3d", *(p + i));
    }

    printf("\n");
    free(p);
    return(0);
}

使用const修饰指针变量

const关键字修饰的数据类型是指常类型,最简单的用法是用来定义const
常量,具有不变性,const修饰的常量在声明的时候就要进行初始化赋值,不然后面是不能赋值的

  • int const *a; //修饰指向的内容,a可变,a指向的内容不可变
  • int *const a; //修饰指针a,a不可变,a指向的内容可变
  • const int *a; //修饰指向的内容,a可变,a指向的内容不可变
  • const int *const A; //指针a和a指向的内容都不可变

No.13 结构体

结构体类型定义

struct student{
    int id; //学号
    char name[20]; //姓名
    char sex[4]; //性别
    int age; //年龄
};

结构体变量定义

  • 先定义结构体类型,再定义结构体变量
struct sudent{
    int id; //学号
    char name[20]; //姓名
    char sex[4]; //性别
    int age; //年龄
};
struct student stu1,stu2;
  • 定义结构体类型的同时定义结构体变量
struct student{
    int id; //学号
    char name[20]; //姓名
    char sex[4]; //性别
    int age; //年龄
}stu1,stu2;
  • 省略结构体名称,直接定义结构体变量
    struct{
    int id; //学号
    char name[20]; //姓名
    char sex[4]; //性别
    int age; //年龄
    }stu1,stu2;

结构体变量初始化

struct stu1;
stu1 = {10001,‘kernel‘,‘boy‘,18};

结构体变量的访问

  • 使用结构体变量.成员名
  • 使用结构体变量->成员名

结构体访问数组

  • 使用结构体数组[下标].成员名
  • 使用结构体数组[下标]->成员名

No.14 共用体

使用方法和结构体一样

区别

  • 结构体占据连续存储区域,每个成员都拥有自己的存储空间

  • 共用体将不同数据类型的所有成员存储在一段存储区域内,各个成员共享一块存储空间

  • 空间的大小取决于占存储空间最大的那个成员

  • 不同时刻可以表现为不同的数据类型和数据长度,但是同一时刻只有一个成员的值有意义

  • 使用union关键字
#include <stdio.h>

union type{
    int class_id; //班级
    char title[20]; //职称
};

struct Person{
    char name[10]; //姓名
    char sex; //性别
    int age; //年龄
    int flag; //标记用户
    union type t;
};

int main(){
    struct Person person[10];
    int i;
    int num;
    printf("请输入要录入的人员数量:\n");
    scanf("%d",&num);
    for (int i = 0; i < num; i++) {
        printf("请输入ID为%d的用户的信息:\n",i + 1);
        printf("姓名:");
        scanf("%s",&person[i].name);
        getchar();
        printf("性别:");scanf("%c",&person[i].sex);getchar();
        printf("年龄:");
        scanf("%d",&person[i].age);
        getchar();
        printf("标识符:");
        scanf("%d",&person[i].flag);
        getchar();
        if (person[i].flag == 0){
            printf("请输入班级ID:");
            scanf("%d",&person[i].t.class_id);
        } else if (person[i].flag == 1){
            printf("请输入教师的职称:");
            scanf("%d",&person[i].t.title);
        } else{
            printf("输入有误,请重新输入!\n");
            i -= 1;
        }
    }
    printf("输出所有用户的信息:\n");
    for (int i = 0; i < num; i++) {
        printf("输出ID为%d的用户的信息:\n",i + 1);
        printf("姓名:");puts(person[i].name);
        printf("性别: \n");printf("%c",person[i].sex);
        printf("年龄:\n");printf("%d",person[i].age);
        if (person[i].flag == 0){
            printf("学生的班级ID:");
            printf("%d\n",person[i].t.class_id);
        } else if (person[i].flag == 1){
            printf("教师的职称:");
            puts(person[i].t.title);
        }
    }

}

No.15 枚举

我们定义一些变量的时候,比如性别,不是男的就是女的,对于这些可控的变量值,我们就可以使用枚举来表示

#include <stdio.h>

int main(){
    enum sex{
        man,
        woman
    }s;
    char msg[2][10] = {"男性","女性"};
    for (s = man; s <= woman; s++) {
        switch (s){
            case man:puts(msg[man]);
                break;
            case woman:puts(msg[woman]);
                break;
        }
    }
}

No.16 类型定义符

我们可以自定义数据类型,可以通过类型定义符起一个别名

#include <stdio.h>

typedef struct students{
    char name[10];
    char sex;
    int age;
}stu;

int main(){
    stu s1 = {"kernel",‘n‘,18};
}

No.17 文件

  • 分类

    • 存放格式
    • 二进制文件 直接将内存中的数据存到文件中,一般文本编辑器打开该文件会乱码
    • 文本文件 文件内容原样显示,但需要转换成ASCII码保存,占用空间较大
    • 读写方式
    • 顺序文件 每条记录需要按照顺序从头到尾一个接一个存取
    • 随机文件 在文件的任意位置进行读写操作,不用从头读到尾
  • 文件类型指针 FILE结构体变量

  • 文件打开与关闭

    • open 打开文件
    • close 关闭文件
  • 文件读写操作

    • 字符

    • fgetc 字符写入
    • fputc 字符输出
    # 写入
    #include <stdio.h>
    #include <string.h>
    
    int main() {
      FILE *fp;
      char str[] = "Write The Data to File!";
      int index = 0;
      fp = fopen("test1.txt","w");
      if(fp == NULL) {
          printf("文件打开失败!\n");
          exit(1);
      }
      while(index < strlen(str)){
        fputc(str[index++],fp);
    }
      fclose(fp);
      return 0;
    }
    # 输出
    #include "stdio.h"
    
    int main() {
      FILE *fp;
      char c;
      int n = 1;
      if((fp = fopen("test1.txt","r")) == NULL) {
          printf("文件打开失败!\n");
          exit(1);
      }
      while((c = fgetc(fp)) != EOF) 
      { 
          printf("%c",c); n++; 
      } 
      printf("\n"); 
      fclose(fp); 
      return 0;
    }
    • 字符串

    • fgetsc 字符串写入
    • fputs 字符串输出
    # 写入
    #include <stdio.h>  
    
    int main() {
      char str[] = "通过fputs方法往文件中写入信息!"; 
      FILE *fp = fopen("test2.txt","w"); 
      if(fp == NULL) {
          printf("文件打开失败!\n"); exit(1); 
      } 
      fputs(str,fp); fclose(fp); 
      return 0; 
    }
    # 读取
    #include <stdio.h>
    int main()
    
    {
      FILE *fp;
      char str[20];
      if((fp = fopen("test2.txt","r")) == NULL) {
          printf("文件打开失败!\n");
          exit(1);
      }
      while(fgets(str,3,fp) != NULL){
          printf("%s",str);
      }
      printf("\n");
      fclose(fp); 
      return 0;
    }
    • 格式化

    • fscanf 格式化写入
    • fprintf 格式化输出
    # 写入
    #include <stdio.h>
    int main()
    {
      char c[] = "Today is 2014 July ";
      int day = 22; char a = ‘t‘,b = ‘h‘;
      FILE *fp; if((fp = fopen("test3.txt","w"))== NULL) {
          printf("文件打开失败!\n"); exit(1);
      }
      fprintf(fp,"%s%d %c%c",c,day,a,b); 
      fclose(fp); 
      return 0; 
    }
    # 读取
    #include <stdio.h>  
    int main() {
      //这里很容易出问题,所以我并不喜欢用fscanf这个函数 
      char c1[5],c2[5],c3[5],c4[5],c5[5],c6[5]; 
      int day,year; FILE *fp; 
      if((fp = fopen("test3.txt","r"))== NULL) {
          printf("文件打开失败!\n"); exit(1); 
      }
      fscanf(fp,"%s%s%s%s%s%s",&c1,&c2,&c3,&c4,&c5,&c6); 
      printf("%s %s %s %s %s %s\n",c1,c2,c3,c4,c5,c6); 
      fclose(fp); 
      return 0; 
    }
    • 数据块

    • fwrite 数据块写入
    • fread 数据块输出
    # 写入
    #include <stdio.h>
    
    typedef struct
    {
      int id;
      char name[20];
      int age;
    }STU;
    
    int main()
    {
      STU stu;
      FILE *fp;
      char c;
      //内容是追加的!   
      if((fp = fopen("test4.data","ab"))== NULL)
      {
          printf("文件打开失败!\n");
          exit(1);
      }
      while(1)
      {
          printf("请输入学号: ");scanf("%d",&stu.id);
          printf("\n请输入姓名: ");scanf("%s",&stu.name);
          printf("\n请输入年龄: ");scanf("%d",&stu.age);
          fwrite(&stu,sizeof(stu),1,fp);
          printf("\n继续输入?(Y/N)\n");
          getchar();
          c = getchar();
          if(c == ‘y‘ || c == ‘Y‘)continue;
          else break;
      }
      fclose(fp);
      return 0;
    }
    # 读取
    #include <stdio.h>
    
    typedef struct
    {
      int id;
      char name[20];
      int age;
    }STU;
    
    int main()
    {
      STU stu;
      FILE *fp;
      if((fp = fopen("test4.data","rb"))== NULL)
      {
          printf("文件打开失败!\n");
          exit(1);
      }
      printf("输出文件中的内容:\n");
      printf("学生学号     学生姓名        学生年龄\n");
      while(fread(&stu,sizeof(stu),1,fp) == 1)
      {
          printf("%-15d%-15s%-15d\n",stu.id,stu.name,stu.age);
      }
      fclose(fp);
      return 0;
    }
    • getw 字写入
    • putw 字输出
    • feof 检测文件是否结束

    • ferror 执行输入输出时,文件是否出错,返回0则无错

    • clearerr 重新设置文件出错标志,无返回值
  • 文件定位
    • rewind 移动位置到文件开头
    • fseek 根据起始位移动偏移量
    • ftell 返回指针位置

No.18 变量的作用域与生存周期

作用域

  • 局部变量 在函数内部定义说明的,作用域仅限于函数内,函数外无法调用
  • 全局变量 在函数外部定义说明的,在所有函数中都可以调用,例如在main函数外定义结构体

生存周期

  • auto(自动变量) 这个是默认的,我们平时定义的变量都是自动变量

  • static(静态变量) 静态局部变量的初始化是在编译期进行的,如果没有进行赋值,系统默认初始值是0或\0,只能赋值依次,程序运行期间不能释放,生命周期是整个程序的运行周期

  • register(寄存器变量) 对于频繁读写的变量,为了提高程序的运行效率,允许将变量放到CPU的寄存器中,需要时直接从寄存器中取出直接参与计算

C语言从入门到精通,看这一篇就够了

标签:产生   字母   静态变量   strcpy   编译器   寄存器变量   内存分配   控制   tps   

原文地址:http://blog.51cto.com/13559120/2317643

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!