C语言重点复习回顾1
不是新手教程
而是最近自己重新复习而记录下的概念
1.+++i 先运算再赋值
2.i++ 先赋值在运算只作用于变量不能作用于常量或者表达式
3.逗号运算符(for语句)
单独使用可以把初始化代码放在一行
I=1;
J=2
等价于i=1,j=2;
从左到右逐个计算,值为最后一个表达式的值
赋值运算符的优先级比逗号运算符高,所以写成a=3,5即a=3;5;
a=(b=3,(c=b+4)+5)
b为3 ,c赋值成b+4,c加上5,复制给a
虽然有括号但是还是默认从左到右
4.条件运算符
exp1?exp2:exp3
1真返回2
1假返回3
适合简单语句
5.Goto
goto标签
If(i>10)
{ goto A;
}
A: printf{“1111”};
相当于break破坏逻辑
适用于很多层循环从最里面跳到最外面,break只能跳一次
6.数组:类型一致,数量庞大.定义位置最好处在最前面
数组不能动态定义 Int a[n]不能说n,n必须是常量或者是常量表达式 c99可变数组支持
*数组越界常见问题,不会报错,访问的是奇怪的东西
循环和数组
循环一般起始为0因为数组!
Int a[10];
For(i=0;i<10;i++)
{
a[i]=i;}
数组的初始化
Int a[10]={0};第一个为0之后也默认为0,若int a[10];则栈结构随机数
可以给一部分赋值
若初始化过,则可以不写数组长度。若未初始化过则必须!
C99可对指定元素赋值 int a[10]={[3]=2};
7.c没有字符串
但有字符串常量:“11”无法修改
字符数组存放和处理字符串
可以每个元素用单引号括起来
最方便的可以省略大括号
Char str5[]=”i like it”;
字符串处理函数需要<string.h>头文件
如果有现成的函数,尽量不要自己去写
获取长度:strlen 是长度不是尺寸(sizeof) 前者不包含“/0”
拷贝字符串 strcpy(1,2)把2拷到1包括结束符 且需要1的长度足以容纳2,strncpy(1,2,5(长度,不包括/0)) 不能用赋值
连接strcat ,strncat
比较strcmp 是否一致
7.二维数组
二维数组初始化可以把所有值写在一个花括号里,因为线性存储的
二维数组可以对部分元素赋值int a[3][4]={{1},{5}};
如果想全赋值成0则只要在大括号里写一个0即可
也可以指定位置赋值,其余位置自动被赋值为0
可以使用for语句打印把i,j倒过来即可得到转置矩阵
8.指针
指针原理第一步:了解数据在内存中是怎么存储和读取的
变量:
通过变量名来访问内存
内存是一个超级大的字符数组(想象)
每个地址可以存储一个字节的数据
一个整型变量(4个存储单元),每个存储单元一个地址
变量名?为了方便程序员使用
只有编译器知道地址,给一个变量名,然后从地址中把内容都取出来
a
指针变量存放的是地址,普通变量存放的是数据
一个指针四个字节,内存中的值是一个地址
指针存放着某种类型变量的地址,故可以用指针间接访问这个变量
指针变量相较于普通变量知识多了一个星号
类型是存放的地址指向的内存中的数据类型
不同数据类型占用的空间大小不同
取址运算符& 要获取某个变量的地址
Char *pa=&a;
取值运算符*(间接运算符) 要获取指针变量指向的数据
Printf(“%c,%d\n”,*pa,*pb);*符号的重用,在定义时表示指针变量,在其他时候表示指针变量的值 间接访问
避免访问未初始化的指针(未赋值的)野指针
9.指针和数组
scanf("%s",str);//不需要取址符,数组名就是一个地址信息(其实是数组第一个元素的地址)
因为数组是同同一类型的元素按序排列故第二个元素的地址是第一个加上第一个元素所占的空间
指向数组的指针
Char a[]=”lee”;
Char *p;
P=a;
P=&a[0];//两种皆可,不是野指针因为把a的地址给他了,如果是直接赋值没有地址才是野指针
指针的运算
可以对指针变量进行加减运算,这样做的意义是指向指针所在位置向前或者向后第n个元素
对比标准的下标法访问数组元素,这种叫做指针法
不是地址简单加一,而是数组中的下一个元素,因为在之前定义指针=a时用的有类型,相当于告诉编译器应该加几,int相当于加四,char相当于加一
又数组名是地址 printf("p=%c,(p+1)=%c,(p+2)=%c\n",a,(a+1),(a+2));
是一样的哪怕没有把数组定义成指针的形式
字符串常量也是地址(相当于字符串数组)
10.指针和数组的区别
数组名是一个地址,而指针是一个左值(变量?)
指针数组和数组指针
Int *p1[5]; 指针数组(数组优先级高) 首先选优先级高的就是什么 指向整型变量的指针(数组元素都是指针)指针数组输出只能用for?
Int p1[5]={&a,&b,&c,&d,&e};
如果元素每个都是字符串Printf(“%s\n”,p1[i]);指的是字符串,如果是p1[i]取出字符,而不是地址(字符串) 字符串地址关系??
Int (*p2)[5]; 数组指针
数组指针是一个指针,它指向一个数组地址??(元素都为int)
1.数组名是一个地址,数组不是一个地址
2.*p不是指向数组的指针,它指向的是数组第一个元素的地址,而不是指向数组!虽然等于数组名也等于数组地址但概念不同!!
数组所有元素挨个存放,第一个元素知道以后要遍历所有。p指向一个变量而不是一个数组
数组指针才是指向数组的指针 虽然是数组名即数组地址,但这时要用&以表明数组是一个整体
int temp[5] = {1,2,3,4,5};
int (*p2)[5]=&temp;
正确初始化数组指针(可以理解temp是将数组元素看成不同个体来对待,而&temp把整个数组看成一个整体)
指针指向的是一个数组,数组是一个地址,数组指针变量里存放的是一个地址,temp==*p2,**p2即为值
(p2)[5]是一个指针,指向temp的地址
我们要利用指针输出temp
正常应该是()取值,而p2是第一个元素的地址,故(*p)是值
11.指针和二维数组
Array [0][0] Array [1][0] 每个都相当于一维数组
理解成指向包含五个元素数组的指针
解引用 (array+1)==array[1]表示什么?指向第二行的首地址故也是指向包含五个元素数组的指针
printf("(array+1):%p\n",*(array + 1));
printf(“array[1]:%p\n”,array[1]);
printf("*array[1][0]:%p\n",&array[1][0]);
三种是一样的,但最后一组相当于取元素,故要加取址
printf("(array+1):%d\n",(array + 1));相当于元素,也相当于不加取址的上一个
(array+1)+3 == &array[1][3] 地址再向右移动
printf("((array+1)+3)%p\n",((array + 1)+3));
printf(“array[1][3]:%p\n”,array[1][3]);
理解成两个(array+i) == array[i]嵌套的值!!!!!
数组指针和二维数组
解释 int(p)[3] = array;(array)第一行子数组
printf("(p+1):%d\n",(p+1)) ;
printf("(array+1):%d\n",(array+1));
printf(“array[1][0]:%d\n”,array[1][0]);
printf("((p+1)+2):%d\n",((p+1)+2)) ;
printf("((array+1)+2):%d\n",(*(array+1)+2));
printf(“array[1][2]:%d\n”,array[1][2]);
12.void和null类型
1.正常定义void会报错,因为系统并不知道他要占多大的空间
void指针——通用指针可以指向任意类型,任何类型的指针都可以赋值给void指针
将void赋值到另一个指针理论上要进行强制类型转换
int num = 1024;
int pi = #
char ps = “lee”;
void pv;
pv=pi;
printf(“pi:%p,pv=%p\n”,pi,pv);
printf(“pv=%d\n”,(int)pv); 因为要输出的是值,故需要再进行解引用
pv=ps;
printf(“ps:%p,pv=%p\n”,ps,pv);
printf(“pv=%s\n”,(char)pv);字符型则不需要
/*
字符串是指导这个地址然后一个字节一个字节的读下去直到/0
printf(“pv=%d\n”,pv);//这里不行
printf(“pv=%s\n”,pv);//这里是可以打印出来的
*/
函数中用的非常多
2.NULL指针(用于指针和对象)
#define NULL((void*)0)
地址0一般不使用,所以指向0代表不指向任何东西
如果指针你不知道指向哪,那么就初始化为null,解引用的时候先检查指针是否为NULL,缩短调试时间。
NULL不是NUL(ascii 空字符,表示字符串的结尾‘/0’)
13.指向指针的指针
Num-520
P-&num
*p-num-520
Pp-&p
*pp-p-&num
**pp-*p-num-520
指针数组和指向指针的指针
字符串-指向字符的指针,数组每个元素都是指针,每个元素又可以用指针法访问
避免重复分配内存,只要进行一处修改
数组指针和二维数组