C语言复习

C语言复习

Tans 1,544 2019-12-10

数据类型

数据标识关键字

registerstaticautoextern
寄存器变量静态全局变量自动变量外部变量
变量放在CPU寄存器中;只有局部变量和形参可以作为寄存器变量,而全局变量不能定义为寄存器变量自动赋初值0局部变量默认是动态变量引用外部程序文件

数据存储区域

静态存储区动态存储区程序区
1. 全局变量 2. 静态局部变量1.非静态局部变量 2.形参栈区

单精和双精

  1. 区别:**单精度占4个字节,双精度占8个字节 **
  2. 单精度必须要有6为有效数字,即为0.600000
  3. 双精度必须又10位有效数字 即为 0.6000000000
  4. image-20200514115149411

常量

  1. 整型常量

    进制数符号举例
    八进制以0开头032;011
    十进制默认123
    十六进制以0x开头0xF...
  2. 字符常量

    1. 小数形式 :前面可以有正负.小数点左右都可以缺省,但是不能同时缺省
    2. 指数形式:尾数,e或E和指三部分组成。指数必须是整数,尾数不能省略
  3. 字符串常量

    ''\ddd'''\xhh'
    1到3位八进制ASCII所代表的字符1到2位十六进制ASCII所代表的字符
  4. 符号常量

运算符

  1. 指针以及圆括号

  2. 负号 强制类型转换,自增自减 ,取值*,取地址& ,逻辑非!,sizeof()---.>返回所占字节数单位是B

  3. 加减乘除取余

  4. 大于等于 小于等于 小于 大于

  5. 等于 不等于

  6. 逻辑或与&& ---> 逻辑或|| --> 条件运算符?:

  7. 赋值 = ------> 除后赋值 --------> 乘后赋值 ----> 取模赋值 ----------->加后赋值 ------>减后赋值

  8. 常用的数学函数

    sqrt(x) 计算平方根
    exp(x)  计算e的x次方的值
    fabs(x) 计算x的绝对值
    pow(x,y)计算x的y次方的值
    log(x)  计算ln x 的值
    log10(x) 计算lg x的值
    

字符串

  1. 字符串常用函数

使用下面函数必须使用 string.h 库函数

unsigned int strlen(const char *p);//字符串长度的获取 不包含‘\0’
char * strcpy(char *destination,const char *source)//字符串赋值,将source复制到											destination中,返回值是destination的指针
char* strcat (chat * destination ,const char * source)//字符链接。将source链接在的																destination尾部
int  strcmp(const char* str1,const char * str2)//字符串比较。相等返回0,前面大于后边														返回1,后边大于前面返回-1
char *strupr(char * str)//将字符串str中的小写字母改为大写字母,其余字符不变
  1. 字符串赋值

    1. 逐字符初始化
    char  ch[3] = {'a','b','\0'}
    char  ch[3] = {'a','b'}//元素个数小于数组长度,后边自动初始化为‘\0
    
    1. 用字符串常量初始化

      char  ch[] = {“Hello World”}
      char  ch[] = "Hello World" 
      
  2. 注意

  3. 汉字所占用的 字节数为2字节

数组赋值

数组动态内存分配:
  1. malloc方法
void* malloc(unsigned int size)//函数原型,只有size
char *p=(char *)malloc(size)单位是KB
size通常与sizeof进行搭配,返回值是一个指针。
  1. calloc方法

    void* calloc(unsigned int num,unsigned int size)//函数原型 size和num
    char *p = (char *)calloc(num,size);
    同上, size通常与sizeof进行搭配,返回值是一个指针。
    
  2. free方法

void free(void *p)//释放动态空间
  1. realloc方法

    void *realloc (void *p,unsigned int newsize);
    作用:改变指针所指向的地址,变成newsize个字节,返回的是新的指针,
    WARING:新的空间大小一定要大于原来的  ,否则会导致数据丢失
    
指向函数的指针

注意:函数名就是一个函数的入口(首地址)

返回值类型说明符 (*指针变量    名) (形参表);
int (*pf2) () //指向返回值为int,形参不做要求
int (*pf) (int x) //指向返回值为int,形参有且只有一个int类型的函数
int larger(int y ,int x){};//定义一个函数
pf = larger;  //错误,形参不同  ,返回值都是int
pf2 = larger()  //正确,形参不做要求  返回值都是int
(*pf2)(x,y) //函数调用可以直接使用
数组初始化操作
int a1[3] = {1, 2, 3};
int a2[3] = {0};                    *//将数组a2各个元素赋值为0。*```
int a3[] = {2,2,2,2}`
int a4[5] = {1,2,3};//只给前面三个赋值
char s1[3] = {'a', 'b', 'c'};
char s2[] = "abc";
错误赋值如下:
int a4[3] = {};
char s3[3] = "abc" //无法编译数组越界abc是4个字符
int a[5]={ , ,1,2};
int a[5]={1,2};
二维数组初始化极其赋值:
int a[3][3] = {1};//错误,不能一同赋值  应该用循环语赋值
int a[][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};//如果给出全部数组那么第一维的下标可以省略

编程相关的小知识

  1. 有关闰年判断的语句
if(year%400==0 || (year%4==0 && year%100!=0))
	return true;//返回是闰年
  1. 有关质数判断
main{
	int num;
	k=num/2;
	result = true;
	if(num==2)//0和1既不是质数也不是合数
		result = true;
	else{
		for(int i=2;i<k;++i){
			if(num%2==0){
				result = false;
				break;
			}
		}
	}
    return result;
}

格式说明符

输出格式符号:

image-20200427181809500

image-20200427184831852

输入格式符:

image-20200427183921508

注意:

int a=999,b=-123;
printf("%2d",a);//输出999,可以看出当数据域宽大于所定域宽时,所定域宽无效
printf("%u",b)//输出41314154,当一个负数用无符号格式负符号输出时会显示错误
scanf("%5d%5d%5d",&q,&w,&e);//输入12345678910 打引出 12345,67891,0
scanf("%*d",&m);//输入123 m得不到任何值。因为*为条件抑制符第一个输入的输不进去
scanf("%*d%d",&a);//输出第二个得到的值
float a= 123.5678;
printf("%10.1f",a);//右对齐,同时第一位小数四舍五入,多余的小数四舍五入
printf("%p",&a);//打印地址可以使用%p

小知识

  1. 32-->空格 48--->0 65-->A 97-->a
  2. 基本数据类型:整形,实型,枚举,字符型 (其他三个数据类型是构造,指针,空类型)
  3. float单精度浮点数 占4个字节,后边是6位小数
  4. goto是关键字,并且变量命名只能以下划线和字母开头 且只能包含字母下划线以及数字
  5. 格式说明符:%u:无符号输出,int型 unsigned int
  6. 逻辑关系注意逻辑短路问题 与或门的实现
  7. 静态变量赋初值为0 非静态变量的初值是随机值

指针

指针定义

  1. 定义为 (数据类型)* 变量名称

易错点

  1. 关于数组与指针的指向问题

    int arr[10]={2,3,-9,5,7,0,4,-1,6,-7},*p;
      p=&arr[3];
      printf("%p\n",p);//打印p的指针为0061FF00
      printf("%p\n",arr );//打印指针为0061FEF4
      return 0;//F00-EF4=12B
    总结:p所指向的指针为第四个元素的地址
    
  2. 关于行指针和列指针

    a[2[2]; //定义一个二维数组
    a是行地址,&a[0]也是行地址;基类型是int[2]
    a[0],&a[0][0]都是列地址   基类型是int
    
    类型表示形式含义地址运算
    行地址a+i ; &a[i]第i行地址a+i+1 表示下一行地址
    列地址a[i]+j ; *(a+i)+j第i行第j列元素地址*(a+i)+j+1 指向下一个元素
    元素*(*(a+i)+j))第i行第j列元素的值N/A

    **技巧:行地址转列地址加“*”,列地址转行地址加“&”; **

  3. const与指针的结合

    常指针: 
        基类型名 *const 指针名称 = 地址值   // 指针值在经过初始化之后不允许修修改指针的值,也就	是不能将指针赋值给其他地址
    指向常量的指针:
      基类型名 const *指针名  或者是   const 基类型名 * 指针名
        //所指向的内容不允许通过指针进行修改
    
    
  4. 用行指针变量访问二维数9组

    类型标识符 (*行指针变量) [整形常量表达式];
    实例: int (*p)[2]  //p指向长度为2的一维数组
    
  5. 指针数组

    类型标识符 *指针变量名 [整形常量表达式]
    实例: int * p[2];  //指向基类型为指针的数组 
    

    **WARING : 与4中的区别是:[] 的优先级大于 *的优先级 **

  6. 给指针分配内存空间

    #include<stdlib.h>
    1. void * malloc (size_t size) //size为需要分配的内存空间 其中以字节Byte计数 
        int *p = (int *) malloc(n*sizeof(int)) //范例
    2. void * calloc(num_elements , size_elements) //其中num_elements为元素个数 size_elements为元素大小
        int *p = (int *) malloc(n,sizeof(int))//范例
    3. void * realloc(void * pre , new_size) //动态扩大缩小申请的内存
        realloc(p,0) //等同与free
    

    最后一定不要忘记Free

函数及循环体

常用循环体注意事项

  1. for循环中间隔符号为";"
  2. do...while()注意后边的";"
  3. 数组不要越界!

常用排序算法

冒泡排序

  	for (i = 0; i < num; ++i)//有num个元素
	{
		for (j = num-1; j > i; j--)
		{
			if (array[j-1]>array[j])
			{
				temp = array[j];
				array[j] = array[j-1];
				array[j-1]  =temp;
			}
		}
	}

选择排序

for (i = 0; i < num-1; ++i)//循环了num-1次
 	{

 		for (j = i ;j < num; ++j)//指定元素下标
 		{
 			if (array[i] > array[j+1])
 			{
 				temp = array[i];
 				array[i] = array[j+1];
 				array[j+1]  = temp;
 			}		
 		}
 	}

递归算法

  1. 斐波那契数列

    int feibonaqie(int num){
    	if(num == 1){	//基线条件
            return 1;
        }else{
            num += feibonaqie(num - 1); //循环条件
        }
        return num;
    }
    
  2. 辗转相除法

    int a,b //两个数
    int result //最大公约数
    while(1){
    		c = a % b;
    		if (c == 0){
    			result = b;
    			break;
    		}else{
    
    			a = b;
    			b = c;
    		}
    	}
    	//递归方法
    
    int 
    {
    
    }
    

预处理

明确:预处理命令不是c语句 ,凡是以“#”开头的都是预处理命令

  1. 宏名可以嵌套定义

  2. #undef可以取消宏替换

  3. 宏名和形参表外的括号之间不能加空格,否则会将空格以后的字符都作为替代字符串的一部分。

  4. 宏定义时记住把形参和后边表达式的变量加括号

#define Max (a,b)  //中间有空格会被替换
#define Max((a),(b)) (a)>(b)?(a):(b) //保险起见,把变量全部加括号
  1. 文件包含允许嵌套

  2. 文件包含可以用 文件名字可以用<> 或者是 “ ” 包含 两者的区别在于:前者函数首先在函数预定义库中寻找,后者首先在用户库中寻找

  3. 条件编译形式

    //第一种
            #ifdef 标识符 //如果已经引入那么直接进入语句
                程序段
            #else 
                程序段
            #endif
    //第二种  如果没有引入则直接进入第一段语句
            #ifndef 标识符
                程序段
            #else 
                程序段
            #endif  
    //第三种 非0就编译第一段
            #if 表达式
            	语句段
            #else 表达式
            	语句段
            #endif
    /*上面三者的条件是各个语句必须单独成行*/
    
  4. 函数调用是在程序运行时进行的,调用时为形参分配内存空间;而宏展开则是在编译前进行的,宏展开时不为形参分配内存空间。

文件

文件类型分类

  1. 纯字符文件也叫文本文件(ASCII文件)占用的内存比较多,一个字节代表一个字符
  2. 二进制文件

文件流分类

  1. 缓冲流 对应缓冲文件系统
  2. 非缓冲流 对应非缓冲文件系统

文件操作之字符流文文件

注意:文件操作的头文件是stdio.h

  1. 文件的打开与关闭

    1. 打开用函数fopen(文件名,文件打开方式) 其中文件名可以是绝对路径
    2. 文件关闭 fclose(文件类型指针);

    image-20200508150744968

    注意7i6你被,9,,w 和 a 操作都可以打开不存在的文件 区别在与追加与否 可以理解为:w为覆盖写,a为追加写
    1. fopen()打开文件错误会返回NULL空指针,NULL在stdio.h中被定义为0
    2. 在输入文本文件时,将回车换行符换为一个换行符,在输出时把换行符换成一个回车符和一个换行符。在操作二进制文件时不需要进行这种转换
    3. w+”为读/写建立一个新的文本文件。这种方式如果指定的文件不存在,则在打开时新建一个以指定文件名命名的文件;**如果指定的文件存在,则将该文件删除,**并建立一个同名的新文件。打开文件后指针指在文件头,此时可以读取数据,也可以写入数据。
    4. “a+”为读/写打开一个文本文件。这种方式只能打开已经存在的文件,如果文件不存在则会出错。打开文件后指针指在文件末尾,此时可以读取数据,也可以写入数据。写入的新数据添加到文件的末尾。
    5. r+”为读/写打开一个文本文件。这种方式只能打开已经存在的文件,如果文件不存在则会出错。打开文件后指针指在文件头,此时可以读取数据,也可以写入数据。
    6. a只能追加数据 不能读
  2. 文件的读8、 。写

image-20200508150658820

//文件初始化操作
File* fp = fopen("test.txt","r");
...
fclose(fp);//注意养成结束关闭所有文件的习惯
//文件写操作(通过字符来实现)
	char ch ;
	if ((fp = fopen("E:\\1\1.txt","a")) == NULL){
		printf("打开文件错误\n");
		exit(0);
	}
	ch =getchar();
	while(ch!='#'){
		fputc(ch,fp);
		ch = getchar();
	}
//文件读操作(通过逐个读取字符来实现)
	char ch;
	ch = fgetc(fp);
	while(ch != EOF){  //其中EOF为末尾标志位
		putchar(ch);
		ch = fgetc(fp);
	}	

//文件写操作(通过逐个读取字符串来实现)
//采用fputs(字符串数据,文件指针)操作;
	char str[20] ;
	if ((fp = fopen("E:\\1\1.txt","a")) == NULL){
		printf("打开文件错误\n");
		exit(0);
	}
	gets(str);
	fputs(str,fp);//写入字符串

//文件读操作(通过字符串来实现)
//fgets(字符数组名,n,文件指针)
//Waring:函数是从文件读取n-1个字符然后在后边添加一个“\0”作为结束的标志 
	char ch[20];
	int n;//指定从文件中读取的字符数量
	if ((fp = fopen("E:\\1\1.txt","a")) == NULL){
		printf("打开文件错误\n");
		exit(0);
	}
	scanf("%d",&n);//读取几个字符
	fgets(str,n+1,str);//读取n个字符然后在末尾添加"\0"
	printf("%s",str);//打印
	fclose(fp);
	}

//指定格式写入  fprintf(文件指针,格式字符串,输出列表)
	double m=1.2;
	int n=1;
	...
    fprintf(fp,"%lf %d",m,n);

//指定格式读出 fscanf(文件指针,格式字符串,输出列表);
	同上
      

字节流文件操作

写文件操作用 fwrite(buffer,size,count,文件指针)
  1. buffer是数据块的指针,是一个写入数据的内存地址;
  2. size每个数据块的字节数 通常搭配 sizeof使用
  3. count是需要写入多少size字节的数据块
  4. 打开文件需要以”wb“方式打开
  5. 如果写入失败返回0,如果写入成功返回count
读文件操作 fread(buffer,size,count,文件指针)
  1. buffer是数据块的指针,是写出数据的地址,通常是 有序链表

其他

  1. rewind(文件指针);作用是让位置指针重新指向文件的开头

  2. fseek(文件指针,位移量,起始点); 起始点用数字标识 调用失败返回非零值

    1. 文件开始 标识符号SEEK_SET 数字为0
    2. 文件当前位置 标识符:SEEK_CUR 数字为1;
    3. 文件末尾 标识符:SEEK_END 数字为2;
  3. ftell(文件指针)先将指针的位置移动到 文件末尾 然后通过返回 位置指针的位置来取得文件的字节数

    调用出错返回**-1**

long l;
fseek(fp,0L,SEEK_END);
l=ftell(fp);
print f;//读取文件的字节数
  1. feof(文件指针)函数 判断文件指针是否在文件末尾,如果在文件末尾则返回非0,否则返回0
  2. ferror(文件指针) 检查文件是否有错误

相关编程题目:

//进制转换之十进制转10进制
	char s[]="0123456789ABCDEF";
	long num;
	char result[100]={0};
	scanf("%d",&num);
	int i=0;
	do{
		result[i] = s[num%16];
		num = num/16;
		i++;
	}while(num!=0);
//倒序打印   

结构体

  1. 定义:
struct 结构体类型名{};//编译器不会为其分配内存空间,
typedef struct Date{} Date //为struct Date起别名 Date 但是还是没有分配内存空间
Date date ; //定义一个结构体变量,为其分配内存,

注意:

  1. 一个结构体变量所占据的内存空间至少是给结构体所有成员所占据的内存的总和,且由于内存对齐等原因,有可能占据更大的空间。`

反码 原码 补码

正数的补码就是其原码,负数的补码就是其反码+1

程序运算的时候是按照补码来相加减的。