浮点数:
x = Mx*2^Ex为一个规格化浮点数,Mx为x的尾数,Ex为x的阶码。
1e-6:表示1 * 10 ^ (-6)。
编译时执行:
sizeof是运算符(而非函数),在编译时执行,不会导致额外的运行时间开销。
三元运算符:是右结合运算。
数据类型:
char:占1个字节 short:占2个字节 int:占4个字节 float:占4个字节 double:占8个字节 一个变量本身定义为常量const时,必须初始化 常量指针:不能通过常量指针修改其指向的值(只是从p的角度来看)。 const int *p; int const *p; 指针常量:指针其本身就是常量(故定义时须初始化),而且也不能通过这个指针修改其指向: int * const p = &a; 数组指针(指向一维数组的指针 / 行指针):char (*p)[10] —— 打括号就是说,先看括号里面的。故可以这样理解: 举例, 二维数组char a[10][10], char (*p)[10];p = a。 首先确定,char (*p)[10]只是将p定义为一个指针(其作用是指向某个数组整体,而不是这个数组中的某个元素);10就是指定了指向的数组的长度 p = a就让p指向了a[0]这个数组;于是p++,就让p指向了下一个数组a[1]; 所以若p = a,那么*p就是获得a[0]这个数组。 既然char (*p)[10]是指向数组的指针,那么通用的使用就是:把数组的地址给p,即char (*p)[10];char s[]="abcd";p=&s; 而二维数组a[][]的数组名a的含义是:a == &a[0]; 指针数组(数组元素是数组):char *p[10] —— 没有括号,所以可以这样看:这是一个数组,其元素类型是char *p。这里是一个放了10个指针的数组。所以p[0]=arrary;是指向数组首元素,而不是整个数组
标准输入输出格式:
当数据的实际位宽大于printf中的指定位宽时,将按照数据的实际位宽输出数据。
//输出 printf("%ld ", test); /* 以长整型格式输出 */ printf("%f ", test); //输出单双精度浮点数 printf("%4.2f ", test); //输出数据共占4位(包括小数点),有2位小数;其他数据类型也是如此(自然有些是没有小数的) printf("%u", n); //n是unsigned int printf("%s ", str); //输出一个字符串 printf("%p , p); //输出地址 //输入 /*scanf:返回值为成功接收到的、输入的变量值个数。 如scanf("%d%d%d",i,j,k,a,b)则只能返回3(因为只能接收三个)*/ char *str = (char *)malloc(N * sizeof(char)); scanf("%s", str); //输入一个字符串 scanf("%lf", &test); //输入双精度浮点数 scanf("%d,%d", &a, &b); //输入必须与指定的格式相同。比如这里有",",那么在Console中输入也需要","
随机数:
//#include <stdlib.h>:rand、srand //#include <time.h>:time srand(0); printf("%d ", rand()); //rand对应于srand,只要srand的种子不变,rand的随机值也不会变;rand的范围是0 - int srand(time(NULL)); //srand(unsigned) printf("%d ", rand()); //time函数返回当前时间(秒);参数param如果不为BULL,则time会将时间赋给param。故这样一来随机数就会一直改变(真正实现随机) printf("%d ", rand() % 100 + 1); //生成1-100的随机数:rand() % 100是0-99
指数函数:
pow(x, y) //表示x的y次方 —— math.h
数组:
初始化:
int count[10] = {0}; //长度为10的数组,全都初始化为0;定义数组时,数组长度只能是常量,不能是变量或含变量的表达式
二维数组:
多维数组在内存中实际上都是一维存储的。例如二维数组,我们只是在逻辑上可以理解为二维的矩阵,但实际上二维数组是一维数组,每个元素还是一维数组,所以整个二维数组都是"一条线"
1、因此int a[3][3]={1...9};int (*p)[3] = a;此时不仅可以*(*p+2),还可以*(*p+8)=*(*(p+2)+2),只要不越二维数组的界(这里是9);
简单点就是:int a[3][3] = {1...9};int *p = &a[0][0];此时可以从头指到尾:头是*p,尾是*(p+8);
2、所以二维数组a有m行n列,则在a[i][j]之前的元素个数为i * n + j —— 因为a[i][j]是第i + 1行,第j + 1列,而前i行都是在a[i][j]之前的
求数组大小:
char s[][20] = { "first", "second", "Third" }; char (*p)[20] = s; printf("%d %d ", sizeof(s) / 20, sizeof(p)); //3、4:因为p要找" ",即' ' —— {"...", "...", "...", " "} //用指针数组 char *p[] = {"How", "are", "you"}; printf("%d ", sizeof(p) / sizeof(char *));
函数:
函数返回值:
printf("%d ", func(-1)); //main函数 int func(int i) { if (i == 0) { return i; } else { printf("h "); //这种情况,会返回printf输出的字符个数(包括转义符):此时return 2 } }
数组作为函数参数,形参数组与实参数组实际上是同一个数组,即传址调用;数组作为实参,只需要写数组名(无论是几维数组)。
变量的生命周期与作用域:
#include <stdio.h> void Incre(); int main() { Incre(); Incre(); return 0; } void Incre() { static int x = 1; //静态:第二次就输出上次,保存的x的值;此外这还是一个局部var,因此作用域还是Incre printf("%d ", ++x); }
字符串:
字符常量与字符串常量的区别:
- 字符串常量:1、字符串里面包含的字符是连续存储的。2、每个字符串都有结束标记(" "),这是一个特殊的字符,即ASCII码为0的字符。3、C语言用字符数组(没有字符串变量)来动态存储字符串,例如char s[10] = {'a', 'b', ' '}是一个字符串,而char s[10] = {'a', 'b'}不是。或者写为char s[] = "abc"(在初始化的情况下可以省略数组大小)。存储多个字符串(用二维数组):char s[][10] = {"星期一", "星期二"}(第一个大小可省略,由字符串的个数,即二维数组中包含数组的个数决定)。
- 字符常量:char s = 'a'。
用指针来访问字符串:
#include <stdio.h> int main() { char *p = NULL; char s[] = "abc"; p = s; //反过来就不行了,因为数组名相当于是一个指针常量 printf("%c ", *p); //现在只是指向字符串的第一个字符 //printf("%s ", *p); //这样是不行的,应该是printf("%s ", p);输出的是这个指针指向字符串的某个字符以及后面剩下的字符,所以p在此时可以用s替代 return 0; }
输入输出字符串:
char s[] = "adjshd"; char s1[] = "casn";char *p = s; char *p1 = s1; gets(p); //可以输入空格 puts(p); scanf("%s", p1); printf("%s ", p1);
但是gets是存在安全隐患的(它没有限制输入的大小,即输入可能超出字符数组的大小,此时就可能把输入存到了指定的字符数组之外的地方):
char s2[] = "sdfjhasjd"; char *p2 = s2; char n = 3; //fgets限制输入的长度 fgets(p2, n, stdin); //最多只能接收n - 1个字符 puts(p2);
getchar函数:
用处1:
#include <stdio.h> #include <math.h> int main() { int n = 0; char c = 'c'; int result = scanf("%d", &n); if(result != 1) //输入与scanf指定的类型不符,则不能接收到。未能成功接收的字符会暂时放在缓冲区 { c = getchar(); //此时getchar就是将缓冲区的字符一次取走一个,并返回 } printf("%d %c ", n, c); return 0; }
用处2:
#include <stdio.h> #include <math.h> int main() { char c = 'c'; //getchar直接从stdin读取一个字符,putchar从stdout输出 c = getchar(); putchar(c); return 0; }
字符串处理函数:
//需要#include <string.h> -- 字符串处理函数strcmp、strlen、strcpy、strcat strcmp(s1, s2); //两个字符串自左向右,逐个字符相比(比较ASCII码),直到出现不同字符或' '为止,此时若:s1==s2;return 0;s1 > s2;return 1;否则return -1. strlen(s1); //返回字符串s1的长度,例如:char s1[10] = "abcde";printf("返回字符串的长度:%d,返回数组的长度%d ", strlen(s), sizeof(s)); char source[] = "hello kit";char destination[] = "world"; puts(strcpy(destination, source));puts(destination);//source->destinations char source[] = "hello kit";char destination[] = "world"; puts(strcat(destination, source));puts(destination);//即destination + source
函数库:
字符处理函数#include <ctype.h>: 函数的参数皆为int,返回也为int int isdigit(int c); //判断是否为数字字符,例如:如果是'3',return 1;是'a',return 0; int toupper(int c); 实用函数#include <stdlib.h> double atoi(const char *s);
double atof(const char *s); //例如: //printf("%6.2f ", atof("1e2"));输出:100.00——还要算上小数点 //printf("%6.2f ", atof("y3")); 输出: 0.00;就算是e3也不会当成是科学计数,而是和y3一样
枚举类型:
#include <stdio.h> int main() { //定义枚举类型,集合{}中的元素,是枚举元素 —— 供枚举变量进行选择 //枚举元素的值:如果没有指定具体值,编译器会把第一个元素处理成0,后面元素以此+1:因此枚举元素是常量 //当然也可以自定义枚举元素的值:例如指定Tuesday = 100,那么Wednesday也遵循+1的原则,因此Wednesday = 101 enum Date { Monday, Tuesday, Wednesday }; //定义枚举变量 //1、直接在定义类型时,顺便把变量定义了 //enum Date { Monday, Tuesday, Wednesday } date; //2、或者只定义变量 //enum { Monday, Tuesday, Wednesday } date; //枚举变量选择具体的枚举值 enum Date date = Tuesday; date = Wednesday; printf("%d ", date); return 0; }
联合union:
编译器处理union时,一个union所有成员共用同一段内存空间(同一时刻,只有一个成员使用内存空间,存放成员值),因此内存空间的大小=最长的成员大小。具体使用如下:
#include <stdio.h> int main() { union { int i[2]; int k; int c; } t, *s = &t; //给哪个成员赋值,内存空间就被这个成员使用 s->i[0] = 10; s->i[1] = 20; printf("%d ", s->c); s->k=30; printf("%d ", s->c); s->c = 1000; printf("%d ", s->c); printf("%d ", s->i[1]);//始终为20 return 0; }
使用联合的一些注意事项:
1、联合不能作为函数参数传递。2、不能整体初始化或者整体赋值,只能对其成员一个一个赋值。3、不能作为函数返回值。
结构体:
#include <stdio.h> typedef struct student { int number; char name[20]; char sex; } S;//此时S是别名 struct { int year; int month; int day; } birth;//此时birth是结构体变量 int main() { S s; s.number = 1000; birth.year = 250; printf("%d %d ", birth.year, s.number); return 0; }
文件操作:
<stdio.h>中的一些变量类型、宏定义:
- 文件结束符:#define EOF (-1)
- 存储文件流信息的类型:typedef struct _iobuf FILE;
- 类型的大小,即sizeof运算符的结果:typedef unsigned int size_t;
打开已存在文件、或新建一个文件:
函数原型:FILE *fopen(const char *filename, const char *mode);//用FILE的指针变量操纵文件 根据打开模式(mode)的不同决定:新建或打开文件 1、文本文件: mode的值:r(打开已有文件,只读)、w(打开文件,只写、覆盖写入,即打开后删除原有内容,重新写入。若文件不存在,则新建)、a(打开文件,只写、追加写入。若文件不存在,则新建) 可读写:r+(打开已有文件,覆盖写入)、w+(新建文件)、a+(打开文件。若文件不存在,则新建。写:追加写入) 2、二进制文件mode:形如ab、ab+
=>每次读写都会从文件游标开始读(第一次读,游标在文件开头),游标属于fp指向的 FILE 变量:因此,对于同一个FILE变量,fgetc的调用也会影响到fgets的读取位置
清空缓冲区数据,并关闭文件:
函数原型:int fclose(FILE *fp); 成功关闭,释放掉文件占用的内存,return 0;发生错误,return EOF(常量,在stdio.h中定义);
写入文件:
写入一个字符:int fputc(int c, FILE *fp); 如果成功,return 刚写入的c;如果失败,return EOF; 写入一个字符串:int fputs(const char *s, FILE *fp); 如果成功,return 一个非负值;失败,return EOF;
格式化写入文件:
//与fputs同理,函数原型:int fprintf(FILE *fp, const char *formatSting, ...); //像printf一样,接受可变长参数,如: fprintf(fp, "%d != %d ", 1, 2);//即写入1 != 2
读取文件:
//与写入同理:int fgetc(FILE *fp) printf("%c ", fgetc(fp)); fgetc(fp);//每调用一次,读取文件的游标,就会向后移动一个char printf("%c ", fgetc(fp)); //读取字符串:char *fgets(char *buf, int n, FILE *fp); //读取n - 1个字符。并将读取到的字符串,复制到字符串变量buf中,最后以 结束 —— buf的长度应不少于n //返回的字符串与buf的值相等 char str[7]; char *buf = str; printf("%s ", fgets(buf, 7, fp));//如果还未读取n个char,就遇到了 或者EOF,则直接结束本次读取(包含 )
直接读取一个单词(从游标开始,到遇到的第一个空格为止,认为是一个单词;游标是读到了这个空格的,因此调用下面的函数后,游标指向这个空格之后):
char buff[255]; //与fprintf不同:%s作为sourceString(不加修饰),buff作为destString fscanf(fp, "%s", buff); fscanf(fp, "%s", buff); printf("%s ", buff);//读到第二个单词
检测当前游标是否指向文件结尾(EOF):
int feof(FILE *fp);//文件结束,return 1;否则return 0;