C语言查漏补缺学习【精简版】

1.scanf函数

scanf("%d %d"//1 2
scanf("price%d %d") //price1 2
// 意思就是scanf函数中,格式是什么,就要对应的输入什么,不然读取不到输入的变量
 

2.常量:const int AMOUNT = 100;

不能再次修改

const int AMOUNT = 100; 
AMOUNT = 90 //会报错,提示AMOUNT只读

3.数据类型

//整数int
printf("%d",...)
scanf("%d",...)
//带小数点的数double
printf("%f",...)
scanf("%lf",...)

4.十进制输入,十六进制输出

int x ;
scanf("%d",&x);
printf("%x",x);

5.使用 if或else后面要加{},因为else是和最近的if匹配。

//当a=7,b=6时,程序的输出是:没有结果。

if ( a=6 )
		if ( b=7 )
				printf("A") ;
else
		printf ("B") :

6.如果在嵌套的for循环中,需要跳出最外层循环,可以使用连续传递break或goto,使用goto时,需要在跳出的位置写 out:

#include <stdio.h>
int main(){
	int one,two,five;
	int x;
	int exit = 0;
	scanf("%d",&x);
	for(one = 1;one < x *10;one ++){
		for(two = 1;two < x *10;two ++){
			for(five = 1;five < x *10;five ++){
				if (one + two * 2 + five * 5 == x *10){
					printf("%d元需要%d个1角,%d个2角,%d个3角\n",x,one,two,five);
					//exit = 1;
					// break;
					goto out;
				}
			}
			//if (exit ) break;
		}
		//if (exit ) break;
	}
out:
	return 0; 
}

7.sizeof( )

(1)是一个运算符,给出某个类型或变量在内存中所占据的字节数。

sizeof(int),sizeof(i)

(2)是静态运算符,它的结果在编译时刻就决定了

(3)不要在sizeof的括号里做运算,这些运算是不会做的。

8.unsigned

(1)如果一个字面量常数想要表达自己是unsigned,可以在后面加u或U。

(2)用l或L表示long(long)

(3)*unsigned的初衷并非扩展数能表达的范围,而是为了做纯二进制运算,主要是为了移位。

9.char

char是一种整数,也是一种特殊的类型:字符。

因为:(1)用单引号表示的字符字面量:‘a’,‘1’

(2)''也是一个字符

(3)printf和scanf里用%c来输入输出字符。

10.逗号运算符:

​ 逗号用来连接两个表达式,并以其右边的表达式的值作为它的结果。逗号的优先级是所有运算符中最低的,所以它两边的表达式会先计算;逗号的组合关系是自左向右,所以左边的表达式会先计算,而右边的表达式的值就留下来作为逗号运算的结果。

​ 一般只在for循环中使用。for(i=0,j=10;i<j;i++,j–)

11.求数组的大小:

int a[]{0};
sizeof(a)/sizeof(a[0]);//得到的是数组的个数。

12.输出变量的地址:%p

int i = 0;
printf("%p\n",&i);

13.C语言printf格式化输入输出:

%c格式化输出单个字符
%p表示输出这个指针
%d表示后面的输出类型为有符号的10进制整型
%u表示无符号10进制整型
%lu表示输出无符号长整型整数 (long unsigned)
%i或%dint
%o八进制
%x十六进制
%X字母大写的十六进制
%e或%E指数
%g或%Gfloat
%n读入/写出的个数
%s字符串
%f或%Ffloat
%a或%A十六进制浮点
%cchar

14.运算符&:

获得变量的地址,它的操作数必须是变量;

15.指针:就是保存地址的变量

int i;
int* p= &i;
int* p,q;        //p是指针,q是普通的int型变量
int *p,q;        //p是指针,q是普通的int型变量
int *p,*ql      //p,q都是指针

16.*:是一个单目运算符,用来访问指针的值所表示的地址上的变量。

17.指针是const

表示一旦得到了某个变量的地址,不能指向其他变量

int * const q = &i;//q是const,q不能指向其他地址
*q = 26; //OK
q ++//ERROR

18.所指是const

表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)

const int *p = &i;
*p = 26; //ERROR!(*p)是const
i = 26//OK
p = &j; //OK

总结:要么是指针不可以修改,要么是通过指针不能修改。

判断哪个被const了的标志是const在 * 的前面还是后面。如果在前面:所指的东西不能被修改,如果在后面:指针不能被修改。

19.将一个非const的值转换成const的

void f (const int* x);
int a = 15;
f(&a); // ok
const int b = a;
f(&b);  //ok
b = a + 1;Error!

当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改。

20.const数组

const int a[] = {1,2,3,4,5,6};
/*
数组变量已经是const的指针了,这里的const表明数组的每个单元都是 const int
所以必须通过初始化进行赋值
*/

22 *p++

  • 取出p所指的那个数据来,完事之后顺便把p移到下一个位置去
  • *的优先级虽然高,但是没有++高
  • 常用于数组类的连续空间操作
  • 在某些CPU上,这可以直接被翻译成一条汇编指令

22.指针比较

  • <.<=,==,>,>=,!= 都可以对指针做
  • 比较它们在内存中的地址
  • 数组中的单元的地址肯定是线性递增的。
  1. 0地址
  • 当然你的内存中有0地址,但是0地址通常是个不能随便碰的地址
  • 所以你的指针不应该具有0值
  • 因此可以用0地址来表示特殊的事情:
    • 返回的指针是无效的;
    • 指针没有被真正初始化(先初始化为0)
  • NULL是一个预定定义的符合,表示0地址
    • 有编译器不愿意你用0来表示0地址

24.指针的类型

  • 无论指向什么类型,所有的指针的大小都是一样的,因为都是地址
  • 但是指向不同类型的指针是不能直接互相赋值的
  • 这是为了避免用错指针。

25.指针的类型转换

  • void*表示不知道指向什么东西的指针
    • 计算时与char*相同(但不相通)
  • 指针也可以转换类型
    • int *p = &i; void *q = (void *)p;
  • 这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量。
    • 当用q看时,不再是int啦,认为是个void!

26.用指针来做什么

  • 需要传入较大的数据时用作参数
  • 传入数组后对数组做操作
  • 函数返回不止一个结果
    • 需要用函数来修改不止一个变量
  • 动态申请的内存
  1. 动态内存分配
#include <stdio.h>
#include <stdlib.h>
int main(void){
  int number;
  int* a;
  int i;
  printf("输入数量:")scanf("%d",&number);
  a = (int*)malloc(number*sizeof(int));
  for(i=0;i<number;i++){
    scanf("%d",&a[i]);
  }
  //逆序输出
  for(i=number-1;i>0;i--){
    printf("%d",a[i]);
  }
  //释放内存
  free(a);
  return 0;
}

28.malloc, #include <stdlib.h>

void * malloc(size_t size);

  • 向malloc申请的空间的大小是以字节为单位的
  • 返回的结果是void*,需要类型转换为自己需要的类型。
  • (int*)malloc( n * sizeof(int))

29.free()

  • 把申请得来的空间还给“系统”
  • 申请过的空间,最终都应该要还
  • 只能还申请来的空间的首地址

30.字符串

  • 以0(整数0)结尾的一串字符
    • 以0或’\0’是一样的,但是和’0’不同,'0’代表ascall码值48。
  • 0标志字符串的结束,但它不是字符串的一部分
    • 计算字符串长度的时候不包含这个0
  • 字符串以数组的形式存在,以数组或指针的形式访问
    • 更多的是以指针的形式
  • string.h里有很多处理字符串的函数
  • C语言的字符串是以字符数组的形态存在的
    • 不能用运算符对字符串做运算
    • 通过数组的方式可以遍历字符串
  • 唯一特殊的地方是字符串字面量可以用来初始化字符数组
  • 以及标准库提供了一系列字符串函数

31.char*

  • 字符串可以表达为char*的形式
  • char*不一定是字符串
    • 本意是指向字符的指针,可能指向的是字符的数组(就像int*一样)

32.空字符串

  • char buffer[100]=" ";
    • 这是一个空的字符串,buffer[0]==‘\0’;
  • char buffer[]=“”;
    • 这个数组的长度只有1!

33.putchar

  • int putchar(int c);
  • 向标准输出写一个字符
  • 返回写了几个字符,EOF(-1)表示写失败

33.getchar

  • int getchar(void);

  • 从标准输入读入一个字符

  • 返回类型是int,而不是char,是为了返回EOF(-1)

    • Windows -> Ctrl + Z
    • Unix -> Ctrl+D

    34.string.h

  • strlen

    • size_t strlen(const char *s);
    • 返回s的字符串长度(不包括结尾的0)
  • strcmp

    • int strcmp(const char *s1,const char *s2);
    • 比较两个字符串,返回
      • 0:s1==s2
      • 1:s1>s2
      • -1:s1<s2
  • strcpy

    • char * strcpy(char *restrict dst,const char *restrict src);
    • 把src的字符串拷贝到dst
      • restrict表明src和dst不重叠(C99)
    • 返回dst
      • 为了能链起代码来
  • strcat

    • char *strcat(char *restrict s1,const char * restrict s2);
    • 把s2拷贝到s1的后面,接成一个长的字符串
    • 返回s1
    • s1必须具有足够的空间
//安全版本,不会出现越界
char * strncpy(char *restrict dst,const char* restrict src,size_t m);
char * strncat(char *restrict s1,const char* restrict s2,size_t n);
int strncmp(const char*s1,const char * s2,size_t m);

35.复制一个字符串

  • char *dst = (char *)malloc(strlen(src)+1);
  • strcpy(dst,src);

36.枚举

  • 枚举是一种用户定义的数据类型,它用关键字 enum 以如下语法来声明:

    enum 枚举类型名字{名字0,…,名字n };

  • 枚举类型名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是常量符合,它们的类型是int,值则一次从0到n。如:enum colors{red,yellow,green};

  • 就创建了三个常量,red 的值是0,yellow是1,而green是2。

  • 当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量的值的名字。

37.结构作为函数参数

  • 整个结构可以作为参数的值传入函数
  • 这时候是在函数内新建一个结构变量,并复制调用者的结构的值。
  • 也可以返回一个结构,这与数组完全不同。

38.自定义数据类型(typedef)

  • C语言提供了一个叫 typedef 的功能来声明一个已有的数据类型的新名字。如:
    • type int Length; 使得 Length 成为 int 类型的别名。
  • 这样,Length 这个名字就可以代替int出现在变量定义和参数声明的地方了:
    • Length a,b,len;
    • Length numbers[10];

39.全局变量

  • 定义在函数外面的变量是全局变量
  • 全局变量具有全局的生存期和作用域
    • 它们与任何函数都无关
    • 在任何函数内部都可以使用它们、
  • 没有做初始化的全局变量会得到0值
    • 指针会得到NULL值
  • 只能用编译时刻已知的值来初始化全局变量
  • 它们的初始化发送在main函数之前
  • 如果函数内部存在与全局变量同名的变量,则全局变量会被隐藏40.

40.静态本地变量

  • 在本地变量定义时加上 static 修饰符就成为静态本地变量
  • 当函数离开的时候,静态本地变量会继续存在并保持其值
  • 静态本地变量的初始化只会在第一次进入这个函数时做,以后进入函数时会保持上次离开的值
  • 静态本地变量实际上是特殊的全局变量(地址放在一个区域)
  • 它们位于相同的内存区域
  • 静态本地变量具有全局的生存期,函数内的局部作业域
    • static在这里的意思是局部作用域(本地访问)

41.返回指针的函数

  • 返回本地变量的地址是危险的
  • 返回全局变量或静态本地变量的地址是安全的
  • 返回在函数内malloc的内存是安全的,但是容易造成问题
  • 最好的做法是返回传入的指针

42.宏

# define 用来定义一个宏
  • 如果一个宏的值中有其他宏的名字,也是会被替换的

  • 如果一个宏的值超过一行,最后一行之前的行末需要加\

  • 宏的值后面出现的注释不会被当作宏的值的一部分

  • 预定义的宏

    __LINE__  //第几行
    __FILE__  //文件名
    __DATE__  //日期
    __TIME__  //时间
    __STDC__  //判断编译器是否符合ANSIC标准,符合时为1,否则未定义
    
  • 像函数的宏

#define cube (x) ((x)*(x)*(x))
  • 带参数的宏的原则
    • 一切都要括号
    • 可以带多个参数,也可以组合(嵌套)使用其他宏
      • 整个值都要括号
      • 参数出现的每个地方都要括号
#define RADTODEG(x) ((x)*57.29578)

#define NIN(a,b) ((a)>(b)?(b):(a))

43.头文件

  • 把函数原型放到一个头文件(以.h结尾)中,在需要调用这个函数的源代码文件(.文件)中引入# include 这个头文件,就能让编译器在编译的时候知道函数的原型。
  • 在使用和定义这个函数的地方都应该#include这个头文件
  • 一般的做法就是任何.c都有对应的同名.h,把所有对外公开的函数的原型和全局变量的声明都放进去
  • 只有声明可以被放在头文件中
    • 是规则不是法律
  • 否则会造成一个项目中多个编译单元里有重名的实体
    • *某些编译器允许几个编译单元中存在同名的函数,或者用weak修饰符来强调这种存在。
  • 同一个编译单元里,同名的结构不能被重复声明
  • 如果你的头文件里有结构的声明,很难做到这个头文件不会在一个编译单元里被#include多次

44.# include

  • 是一个编译预处理指令,和宏一样,在编译之前就处理了
  • 它把那个文件的全部文本内容原封不动地插入到它所在的地方,所有也不是一定要在.c文件的最前面#include

45.不对外公开的函数

  • 在函数前面加上static就使得它成为只能在所在的编译单元中被使用的函数
  • 在全局变量前面加上static就使得它成为只能在所在的编译单元中被使用的全局变量

46.变量的声明

  • int i; 是变量的定义
  • extern int i ; 是变量的声明

47.声明和定义

  • 声明是不产生代码的东西
    • 函数原型
    • 变量声明
    • 结构声明
    • 宏声明
    • 枚举声明
    • 类型声明
    • inline声明
  • 定义是产生代码的东西
    • 函数
    • 全局变量

48.标准头文件结构

  • 运用条件编译和宏,保证这个头文件在一个编译单元中只会被#include一次
#ifndef __LIST_HEAD__
#define __LIST_HEAD__



#ednif
  • 000”#pragma once 也能起到相同的作用,但是不是所有的编译器都支持。

48.打开文件

#include <stdio.h>
int main(){
  FILE *fp = fopen("12.in","r");
  if(fp){
    int num;
    fscanf(fp,"%d",&num);
    printf("%d\n",num);
    fclose(fp);
  }else{
    printf("无法打开文件\n");
  }
  return 0;
}

49.二进制文件

  • 其实所有的文件最终都是二进制的
  • 文本文件无非是用最简单的方式可以读写的文件
    • more、tail、cat、vi
  • 而二进制文件是需要专门的程序来读写的文件
  • 文本文件的输入输出是格式化,可能经过转码

50.位段

  • 可以直接用位段的成员名称来访问
    • 比移位、与、或还方便
  • 编译器会安排其中的位的排列,不具有可移植性
  • 当所需的位超过一个int时会采用多个int
  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值