根据coder-pig(http://blog.csdn.net/coder_pig)的博客学习整理,感谢!
基础知识
1.C语言程序的转换过程
注解:①当我们在编译器上把代码写好,此时的文件是Hello.c, .c是C语言程序源代码的后缀,此时的程序叫源程序!
②当程序通过编译器进行编译时,此时产生一个目标程序(二进制的代码文件)
③将目标程序和库文件链接成机器码文件,就是exe可执行程序!
④点击运行,输出结果!
2.学习路线图:
关键字(保留字)
①何为关键字:C语言中具有特殊含义的英文单词~通常用于构成语句,存储数据,定义数据类型等
②C语言的32个关键字参照图,不用记!等用到了再去了解!
变量的使用:
一个简单的 int a = 123;其实暗地里执行了以下操作
①int a:在内存中开辟了四个字节的内存空间,并且为这个空间起了个名字,叫做a;
②后面的=123,这一步完成的是变量的初始化,就是通过a这个变量名,往4个字节的内存中放入123这个数据
小提示;①一个好的建议是,当我们定义一个变量时,对其进行初始化,可以有效的避免空指针问题的出现
②你可以通过&a获得存放123这个数据的内存地址的值!
算术运算符
4.2 关系运算符
4.3逻辑运算符
4.4 赋值运算符
4.5 条件表达式
4.6 逗号表达式:
4.7 长度测试运算符
sizeof:通常用来测试某个数据类型所占的内存空间大小
使用示例代码:
- #include <stdio.h>
- int main()
- {
- int a = 1;
- float b = 1.1;
- char c = 'c';
- printf("%d,%d,%d\n",sizeof(a),sizeof(b),sizeof(c));
- return 0;
- }
该代码测试的是int,float,char类型在本机所占的字节数
4.8 运算符的优先级
口诀: 括号最大 > ! > 算数运算符 >关系运算符>逻辑与或>赋值运算符
基础语法与结构化程序设计
学习路线图:
正文:
1.字符输入/输出函数
2.格式输入/输出函数
跟前面的单个字符的输入输出不同,当我们用到printf()和scanf()两个函数的时候就需要,
将头文件包括到源文件中,#include <stdio.h>这个就是标准输入输出的的缩写,h是header缩写
可以写成:#include "stdio.h"或者#include <stdio.h>两种方式,看个人喜欢
格式输出函数printf()
何为格式输出:就是按自己想要输出的标准输出,如:保留2位小数
ps:修饰符和格式符较多,刚开始的时候不容易掌握,推荐自己编写程序来验证与理解他们的作用,写多了,就会了!
格式输入函数:scanf()
格式输入,同上,不过是从键盘上将数据传送到某个内存空间中!
scanf()的完整用法:
看图的话或者大家还有些疑惑,这里就演示下scanf的用法吧
scanf使用代码演示:
- /*
- 该代码演示的scanf的用法,特别注意第三点,别在
- scanf里乱添加空格,逗号等符号,不然输入的时候
- 就需要把他们按格式写上,不然会造成莫名奇妙的问题
- */
- #include <stdio.h>
- int main()
- {
- int a,b,c;
- //1.正常的scanf的用法
- scanf("%d%d%d",&a,&b,&c);
- printf("a = %d b = %d c = %d\n",a,b,c);
- //2.使用*抑制符跳过输入的某个值
- scanf("%3d%*2d%2d%3d",&a,&b,&c);
- printf("a = %d b = %d c = %d\n",a,b,c);
- //3.最好不要在scanf里面写逗号和空格之类的,不然输入
- //输入的时候必须把这些都写上
- scanf("%d,%d,%d",&a,&b,&c);
- printf("a = %d b = %d c = %d\n",a,b,c);
- return 0;
- }
运行结果:
3.三种基本的程序结构:
顺序结构与判断结构if的使用:
判断结构switch的用法:
3.循环结构:
4.流程跳转控制语句:
break语句:只能用在循环语句与switch(开关)中,用于跳出switch或者跳出循环;而在多层循环中,仅仅跳出一层循环!
continue语句:跳过循环体剩下的部分,直接进入下一次循环。
C语言中的数组
学习路线图
1.一维数组与二维数组:
2.字符串与字符串数组
小结:
①数组是用来存储数据类型相同的变量的有序集合,可以通过下标访问数组中的元素
②一维数组的定义,初始化与引用
③二维数组用于存储表格数据,定义,初始化与引用
④区分字符串与字符串数组的区别,字符串是要用字符数组存储,最后还要加上一个'\0'
⑤字符数组的长度至少比字符串大一
⑥使用sizeof(数组名)/sizeof(数组元素的数据类型)求出字符数组的长度
⑦字符数组直接==比较的结果是比较地址
⑦使用string.h库提供的字符串操作函数:
strcpy(a,b) 将b的字符串复制到a中,会覆盖 strcat(a,b):将字符串b的内容拼接到a的后面
strcmp(a,b):将a,b两个字符串从左到右对每个字符,按照ascII码的值,进行比较;直到出现不同或者'\0',终止比较
如果内容一样,返回0;a 大于 b返回正整数 ; a 小于 b返回负整数
strlen(a):返回字符串的长度,不包括字符串的结束标志 '\0'
C语言中的指针 -- 灵魂
学习路线图:
指针概念,指针与一维数组与字符串:
指针与二维数组:
该知识点是指针的难点,其实要弄懂这里的话,我们只要把重心放到二维数组上,对二维数组进行彻底的理解!
step 1:二维数组是按行与列存储数据的;我们可以看成若干行 + 每行若干列的一维数组组成
int a[3][4] ={{1,2,3,4},{1,2,3,4},{1,2,3,4}}; 可以看成三行,每行有四个一维数组
step 2:a代表二维数组首元素的地址,即&a[0],如果换行数组的第二,三行的话,只需要:a + 1,a+2这样;等于&a[1],&a[2]
step 3:我们可以把a[0]看做是指向a[0][0]的指针,那么a[0]+1则指向a[0][1],即此时的地址为&a[0][1]
ps: 这里的+1的1是数组元素所占的字节数,比如int a[]的话,那么这个+1代表的就是向后移动4个字节,指向的就是下一元素;
如果是+2的话就是后移8个字节,所以a[i][2] = a[i] + 2
step 4:通过前面一维数组的学习,我们可以知道 a[i] 与 *(a+i)等价
同样的,我们扩展到二维数组的情况 a[i][j] 与*(a+i)+j 和a[i]+j是等价的,都是表示a[i][j]的地址
而求a[i][j]的值: *(a[i]+j) 与*(*(a+i)+j)都是可以的
注意:*a 与*(a+i)都不代表任何具体的数组元素,所以当你们引用他们的时候可能会引起错误哦!
①数组首地址a[0]: a 不可以直接引用!!!
②一维数组a[0]首元的地址(&a[0][0]): a[0],*(a+0),*a;
③第一行的首地址: a + 1 同样不可以直接应用
④一维数组a[1]首元的地址(&a[1][1]): a[1],*(a + 1)
⑤序号为2行4列元素a[2][4]的地址:a[2]+4,*(a+2)+4,a[2][4]
代码示例:
①指向数组元素:
运行截图:
②指向数组
运行截图:
小结:
①指针的概念,指针变量,直接访问与间接访问
②指针的基本使用
③指针与一维数组
④指针与字符串
⑤指针与二维数组
C语言复杂数据类型
学习路线图:
本节正文
函数
ps:空函数就是什么都不做的函数,开发过程中不需要马上实现的,先写空函数!简单的空函数:void abc(){ }
结构体
共用体:
代码示例2:
建立一个共用体类型,当输入的时学生类型时,要求输入的是学生id,当输入的是老师类型的时候,要求输入老师职称
代码如下:
- <span style="font-family:Microsoft YaHei;">#include <stdio.h>
- union type
- {
- int cid; //班级
- char title[20]; //职称
- };
- struct Person
- {
- char name[10]; //姓名
- char sex; //性别
- int age; //年龄
- int flag; //标志是老师还是学生
- union type tp;
- };
- int main()
- {
- struct Person person[10];
- int i;
- int num;
- char ch;
- printf("请输入要录入的人数:\n");
- scanf("%d",&num);
- for(i = 0;i<num;i++)
- {
- printf("请输入第%d个人员的信息:\n",i + 1);
- printf("姓名: ");scanf("%s",&person[i].name);getchar();
- printf("性别: ");scanf("%c",&person[i].sex);getchar();
- printf("年龄: ");scanf("%d",&person[i].age);
- printf("职业标识符: ");scanf("%d",&person[i].flag);
- if(person[i].flag == 0)
- {
- printf("请输入学生的班级id: ");
- scanf("%d",&person[i].tp.cid);
- }
- else if(person[i].flag == 1)
- {
- printf("请输入老师的职称: ");
- scanf("%s",&person[i].tp.title);
- }
- else
- {
- printf("输入有误,请重新输入!\n");
- i -= 1;
- }
- }
- printf("\n输出所有录入人员的信息:\n");
- for(i = 0;i<num;i++)
- {
- printf("输出第%d个人员的信息:\n",i + 1);
- printf("姓名: ");puts(person[i].name);
- printf("性别: ");printf("%c",person[i].sex);
- printf("\t年龄: ");printf("%d",person[i].age);
- if(person[i].flag == 0)
- {
- printf("\t学生的班级id: ");
- printf("%d\n",person[i].tp.cid);
- }
- else if(person[i].flag == 1)
- {
- printf("\t老师的职称: ");
- puts(person[i].tp.title);
- }
- }
- return 0;
- }</span>
运行截图:
C语言枚举:
类型定义符(typedef)
小结:
1.函数
①函数的引入,分类,定义使用,函数声明
②函数的传值与传址
③函数的嵌套与递归
2.结构体
①结构体的引入,类型定义与结构体变量的定义
②结构体变量的初始化,引用(通过.)
③结构体数组的使用
3.共用体
①共用体与结构体的异同
②共用体的理解
③共用体的使用
4.枚举
①枚举的引入,使用,枚举值
5.类型定义符
typedef(定义数据类型别名)
通常用的比较多的是定义结构体的别名!
C语言指针进阶
本章引言:
在前面第5节中我们对C语言的指针进行了初步的学习理解;作为C语言的灵魂,
C指针肯定没那么简单,在这一节中,我们将会对指针进行进一步的学习,比如二级指针,
指针数组,内存分配和const修饰指针常量等!下面就请大家跟随笔者的脚步,对
C指针神秘的一面进行进一步的解析吧!
本节学习路线图:
函数与指针:
①指针作为函数的形参:
②指向函数的指针:
③指针函数:
④带参数的主函数
ps:该代码的运行:先要编译生成exe文件后,来到exe所在文件目录下:输入: 文件名 one two three
会输出:one two three
指针数组:
两个问题:如何保存一个字符串?如果保存的不止一个,而是多个呢?
第一个问题:
①char name[20] = "~~~" ②char *name = "~~~" //前者定义了长度,不能直接赋值,明显后者比较灵活
第二个问题:见图
二级指针:
内存的动态分配:
代码示例:
动态分配10个整型的空间大小,如果大于这个数目则动态分配,否则利用realloc重新分配内存
ps:代码没问题,vc6一直报运行时错误,如果出错了,用C-Free或者Visual studio等编译器试试!
- <span style="font-family:Microsoft YaHei;">#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 < N;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;
- }</span>
使用const修饰指针变量
我们都知道使用const修饰一个基本数据类型的变量,可以让变量存储的值从头到尾都不变
我们的程序不能进行修改!不过修饰指针变量就有点差异了:
比如:
int a = 3,b = 4; const int *p = &a;
如果我们再添加一句代码: p = &b;的话就会报错
如果添加: a = 5;代码并不出错,此时 *p == a == 5;
分析结果:
使用const修饰指针时,表明该指针是一个常量指针,它所指向的变量的值是可以修改的;
但是修改指针指向的地址则是错误的!!!
在C许多的标准库函数都将某些指针参数的类型前加上const,目的是保护参数!
ps:int *const p = &a; const int * const p = &a; 和上面的都是等价的!
本章小结:
①函数与指针:
1.指针作为函数的形参: 指针参数对应的实参需要为变量地址
2.指向函数的指针:函数的首地址称为函数的指针,通过函数名可以找到并且执行函数
3.指针函数:返回值类型是一个指针
4.带参数的主函数: int main(int argc,char *argv[]) :形参依次为:记录参数个数和存储参数内容的字符串数组
②指针数组
二维数组存放字符串与指针数组存放字符串的比较
③二级指针
指向指针变量的指针
④内存的动态分配:
1.内存分配图
2.C语言提供的四个内存分配函数的使用:malloc(),calloc(),realloc(),free()的使用
⑤使用const修饰指针变量
可以修改的指向地址的变量的值,不能修改的是指针所指向的地址!
C语言位运算与文件
学习路线图:
位运算:
ps:位运算符并不改变变量自身的值,可以在运算符后加上等号: a &= b
等同于a = a&b !
文件:
文本文件的使用方式:
"r" | 只读方式打开一个文本文件,只允许度数据,不存在则打开失败 |
"w" | 只写方式打开或建立一个文本文件,只允许写数据 |
"a" | 追加的方式打开一个文本文件,可在文件尾写数据,不存在则创建一个 |
"r+" | 读写方式打开一个文本文件,允许读写,不存在,打开失败 |
"w+" | 读写方式打开或建立一个文本文件,允许读写 |
"a+" | 读写方式打开文本文件,在文件末尾追加数据,不存在则创建一个 |
ps:对于二进制文件,对应的只要改成在每个后面加上一个b就可以了:
如: r --> rb r+ = rb+
文件详细学习图:
使用代码示例:
①单个字符写入/读取
写入: fputc()
- <span style="font-family:Microsoft YaHei;">#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;
- } </span>
读取:fgetc()
- <span style="font-family:Microsoft YaHei;">#include "stdio.h"
- int main()
- {
- FILE *fp;
- char c;
- int n = 1;
- if((fp = fopen("test1.txt","r")) == NULL)
- {
- printf("文件打开失败!\n");
- exit(1);
- }
- //EOF是文件结尾的标志,此处是判断是否到文件尾
- while((c = fgetc(fp)) != EOF)
- {
- printf("%c",c);
- n++;
- }
- printf("\n");
- fclose(fp);
- return 0;
- } </span>
运行截图:
ps:如果不写完整路径的话,比如:d:\\c_code\\day 8的话,会在代码所在的目录下生成对应的文本文件!
②读写一个字符串:
写入fputs()
- <span style="font-family:Microsoft YaHei;">/*
- fputs(字符串,fp)
- 作用:向fp所指的文件中,将字符串写入,'\0'并不写入!
- */
- #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;
- }</span>
读取:fgets()
- <span style="font-family:Microsoft YaHei;">/*
- fgets(字符串数组,n,文件指针)
- 就是:从fp执指向的文件中读取一个长度为n - 1的字符串,
- 存储在一维字符数组中 ,因为字符串会默认添加一个'\0'
- */
- #include <stdio.h>
- int main()
- {
- FILE *fp;
- char str[20];
- if((fp = fopen("test2.txt","r")) == NULL)
- {
- printf("文件打开失败!\n");
- exit(1);
- }
- //这里写3是因为,汉字是占2个字节的
- while(fgets(str,3,fp) != NULL)
- printf("%s",str);
- printf("\n");
- fclose(fp);
- return 0;
- }</span>
运行截图:
③格式化读写函数
这个和之前学的scanf()和printf()使用方法一样,但是,前者是针对内存中的数据的;
而fscanf(0和fprintf()则对应文件读写的!
ps:要注意哦!fprintf是将控制台的内容打印到文件中哦!所以是写入
fscanf()是将文件中的内容输入到控制台哦! 所以是读取
写入fprint:
- <span style="font-family:Microsoft YaHei;">#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;
- }</span>
读取fscanf()
- <span style="font-family:Microsoft YaHei;">#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);
- }
- //这个要按照读取的文件的格式写,我弄了N久还是不行
- //就直接用6个字符串了...
- 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;
- }</span>
运行截图:
二进制文件的读写
示例代码:将学生信息存储到结构体中,然后通过fwrite()函数将结构体内容写入文件中;
在通过fread()函数读取出来
①数据块方式写入:
示例代码:
- <span style="font-family:Microsoft YaHei;">#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;
- }</span>
运行截图:
②数据块方式读取:
示例代码:
- <span style="font-family:Microsoft YaHei;">#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");
- //从fp指向的二进制文件读取数据,每次读取大小为size个字节的数据
- //执行 1 次;最后将这些数据保存到结构体变量的地址内存中
- //返回值正常时是读取的数据库个数(count)的值,否则返回0(错误或文件尾)
- while(fread(&stu,sizeof(stu),1,fp) == 1)
- {
- printf("%-15d%-15s%-15d\n",stu.id,stu.name,stu.age);
- }
- fclose(fp);
- return 0;
- }</span>
②字输入/输出函数
getw和putw两个函数并不是ANSI C标准定义的函数,但很多的C语言编译系统都提供这两个函数,
如果没提供也可以自己写,这个用的不多,就不给出代码示例了,只给出函数用法:
putw(n,fp):以二进制的形式将一个int类型的数据写入到fp所指向的二进制文件中!
n为写入的整数,执行正常返回写入的整数,否则返回EOF
getw(fp):从fp指向的二进制文件中以二进制的方式读取一个字
执行正常返回所读取的二进制整数,否则返回EOF
本章小结:
①位运算:
1.什么是位运算,位运算的6个运算符的作用
2.位运算的使用,原码,补码与反码的概念
3.位运算的相关应用(代替乘法运算,不使用中间变量等)
②文件
1.为什么要用文件?文件的分类
2.文件类型指针 FILE *fp;
3.文件打开关闭: fopen()打开 fclose()关闭
4.文件的读写操作 1)字符读写:fgetc 和 fputc 2)字符串读写:fgets 和 fputs
3)格式化读写:fscanf 和 fprintf 4)数据块读写:fwrite 和 fread
5)字读写(整数) getw和putw
5.文件定位: rewind(fp) 移动指针到文件头 fseek()将指针移动到某个地方
ftell(fp) 返回指针的相对位移量
6.文件状态检查函数:feof(fp)文件是否结束 ferror(fp)执行输入输出时文件是否出错,返回0表示没出错
clearerr(fp):重新设置文件出错标志,无返回值