调试的方式:
1.在纸上列出所有的变量,模拟程序的运行。这种适用于程序不适合在机器上运行的情况
2.在程序中输出变量的值,加上一些运行位置的标志
单一出口原则:
有些程序设计成单一出口原则更好,便于理解
活用/和%运算
对于一串整数比如2561,/10意味着去掉右边的1位即得到256。%10意味着得到右边的第一位即得到1.
C语言的类型:
1)整数:char,short,int,long,long long
2)浮点数:float,double,long double
3)逻辑:bool
4)指针
5)自定义类型
sizeof运算符:
sizeof(类型/变量)得到变量的类型或者类型在内存中占据的字节数。sizeof是静态运算符,它的结果在编译的时刻就决定了,所以不要在sizeof的括号里做运算这些运算不会做
unsigned:
表示数据在内存中不以补码的方式表示(即最高位的1不表示符号位而不是数据位),这样带来的效果就是不能表示负数但是正数表示的范围会扩大。这个符号设计的目的是为了做纯二进制数的运算即移位。一个字面常数想要表达自己是unsigned的,可以在后面加u或者U,用l或者L表示long。
函数原型:
c语言使用函数之前需要知道函数的样子。这个时候就需要再使用之前定义函数的原型:函数头加上;分号结尾就构成了函数的原型,而具体的函数的定义位置则可以放在使用函数的位子之后。函数原型包括的项:函数的名称,参数(参数及类型),返回类型
函数原型的参数如果为()表示参数不确定,如果确定了函数是没有参数的,原型的参数应该写成这样(void)。
函数:
每个函数都有自己的变量空间,参数也位于这个空间中,和其他函数没有关系
变量的作用域就是大括号为范围,在嵌套的块(大括号)中,c语言运行定义同名的变量,但是里面块的变量会覆盖外面的,这一点和java,C#语言是不同的,后者杜绝了这种方式,防止用户出错
main函数:
main函数返回的int是有含义的,返回为0表示正常运行,返回其他非0数后,操作系统可以根据这个返回值进行具体的操作
数组:
得到数组的长度:sizeof(数组)/sizeof(数组的第一个元素)。
数组变量本身不能被赋值(原因是该数组变量是const的指针),如果要把一个数组的所有元素交给另一个数组,必须采用遍历的方法(这一点和java是不一样的,java可以直接赋值)
数组作为函数参数时,不能在[]中给出数组的大小(原因是该数组变量接受的是传递进来的数组的地址);不能再利用sizeof来计算数组元素的个数(原因也是因为接受的是地址),所以往往必须再用另一个参数来传入数组的大小。(这一点和java语言也是不一样的,java语言数组可以直接传递,且可在使用length属性获得传递数组的长度)
二维数组需要a[i][j]来定位,a[i,j]=a[j],因为,号是运算符,结果为右边的数
&运算符:
作用:获得变量的地址,它的操作数必须是变量,输出地址的时候应该使用printf("%p",&i); 将地址强转为int类型后的结果不一定和地址本身相等,这个和计算机是什么架构有关,比如32位还是64为
指针:
专门用来保存地址的变量比如int *p或者int* p;
*号运算符:
*和指针一起使用,表示的是指针所指向的内存单元的内容,即变量的值。
从上面可以看出&运算符和*运算符互为反作用
数组和指针:
函数参数中的数组实际上是指针,但是可以用数组的运算符[]进行运算。所有在函数参数中 int *a 和int a[] 是等价的
数组变量是特殊的指针,数组变量本身表达地址所以,int a[10];int *p = a;//无需用&取地址;
但是数组的单元表达的是变量,需要用&取地址所有a=&a[0];
[]运算符可以对数组做,也可以对指针做,p[0] = a[0];
*运算符可以对指针做,也可以对数组做,*a = a[0];
数组变量是const的指针,不能被赋值
指针是const:const在*号后面,比如int *const p; 表示指针不能修改,但是*p可以修改
指针指向的内容是const:const在*号前面比如 const int* p或者int const* p;表示*p不能修改,p可以修改
const数组: const int a[] = {1,12,4,5};数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int 所以必须通过初始化进行赋值,这种类型的数组是受保护的。
指针运算:
一个指针加1其实是加上了一个sizeof(指针所值的类型所占的字节数),比如int类型 则p+1就是+上4(32位机器上),指针加1意味移动到下一个存储单元
俩个指针相减得到的结果是俩个地址的差的结果/sizeof(类型)。即相差几个类型长度的存储单元的个数
++的优先级高于* ,所有*p++ 是*p 后 *(p+1).
指针不能做乘除,可以加减和比较
0地址:
逻辑地址,不可用。可以用0地址来做特殊的事情,比如返回指针无效,指针没有真正初始化
用NULL(大写,小写没用)表示0地址。
动态内存分配:
malloc(存储单元的个数*类型的sizeof),返回 void*。用来动态分配内存空间,需要include <stdlib.h>。同时申请的到内存空间,一定要free(指针),不然大的系统一直在运算的话可能崩溃
字符串(c语言出现的早,那个时候主要是计算数值,而现在的处理的多的是文字,所有c语言处理字符串的能力不如现代的语言比如java):
以0(整数0)结尾的一串字符,0或者'\0'是一样的,和字符‘0’是不一样的
0标志字符串的结束,但是它不是字符串的一部分,计算字符串长度的时候不包含这个0
字符串以数组的形式存在,以数组或指针遍历的形式访问,更多的是以指针的形式
string.h头文件中包含很多处理字符串的函数
字符串字面量(比如“hello”)可以初始化字符数组
c语言会把俩个相邻的字符串常量自动连接起来
char *s = "Hello World";这个指针本质上是char const *s,由于编译器的原因不需要加上const。
char s[] ="Hello World";这个可以修改,因为字符串就存放在我这里
那么选择用指针的形式表示字符串还是用数组的形式表示字符串呢?
数组的方式表达:字符串可以被修改,作为本地变量空间会被自动回收(动态分配的需要free)
指针的方式:处理参数,以及动态分配空
以上:如果要构造一个字符串用数组,如果要处理一个字符串用指针
scanf读入一个单词(即读到空格 tab 或者回车为止)
本地变量不会被初始化,里面有啥就是啥
字符串数组:
char **a:表示a是一个指针,指向另一个指针,那个指针指向一个字符串,不代表字符串数组
char a[][] :列数一定要指明。