1、数组的意义和形式
数组是什么?数组是一个连续性存储的容器。就类似我们在超市用的临时存储柜,都是一连串的柜子。
格式是名字【大小】;比如我现在我创建一个有8个柜子的临时存储,a【8】;
作用就是用来存储我们的数据。
2、数组的初始化和赋值
#include<stdio.h>
int main(){
int a[7]={4,2,1,5};
int b[3]={0};
int c[4]={0};
c[0]=1;
c[2]=5;
}
a数组的用大括号来写,就会按顺序从序号为0开始放,因为数组是以0开始的,所以你这里为7大小,但是4会放在a【0】,2放在a【1】,1在a【2】,5在a【3】。后面的编译器会自动给你补上0,那么最后一个就是a【6】=0;没有a【7】。当然你也可以去访问a【7】,不过这已经属于访问数组外的了,会出现bug。
b这样做是因为可以把b的所有箱子都补上0.
数组的赋值就是想c一样。c【序号】=值。
3、二维数组
想一下我们可不可以8个箱子为一个存储柜,我们创立3个柜子,那么我们就会有3*8=24个箱子。
这就是二维数组了,形式 :类型 名字【大小】【大小】;比如int a【3】【8】;
4、二维数组的赋值和初始化
a={2,3,5,7,8,9,4,66,88,1,33};或者a={{3,4},{22,11}};第一种方式是按顺序,先把第一个柜子的8个填满,在开始第二个。那么第二种方式是{}表示一个柜子,3和4放在第一个柜子,22和11放在第二个柜子。其他都会补0.
那么赋值更简单了,相当于加多一个【】,a【0】【2】=7;相当于第一个柜子的第3个箱子放5.
那么我相信三维数组你也能推导出来,甚至更高维的。
5、指针(c语灵魂的地方)
指针相当于是一个专门类似int类型的,但指针是专门存地址的。
形式 类型 *名字。比如 int a=4;int *p=&a;指针的类型表示它只能存整数数据的地址,若a是float类型,那么就不可以存储。这里的&是取地址符,那这里就是在说,把a的地址取出来,给p来存储。比如现在a的地址是0x0117,那么现在p==0x0117,或者写成p=&a,那么*p=a。
这里给大家提一个小建议,你可以把*作为正电子,而&为负电子,那么放在一起就直接中和没掉。
*p=*&a=a;
这里还有一个东西叫做空指针,NULL,p=NULL;那么这个指针就指向了空的,就是谁都不指向。相当于a=0;
6、指针的指针
int **pq。两个星号,这个只能用来存储一个星号的指针的地址pq=&p;千万不要写成pq=p,因为p=&a,就会变成pq=&a,很明显这是不对的。那么想通过pq来使用a,那么上面说到的*&的正负电比喻就很有用。因为pq==&p==&&a,那么就可以写成**pq==**&p==**&&a==a;
想必3个星的指针你应该也懂了。其实我个人感觉指针的运用更像是在做数学的代数化简。
7、指针与数组的结合。(这里我感觉也是数学的代数和化简)(这里比较重要,耐心看)
首先要明白数组名字就是该数组第一个箱子的地址。比如nt a【6】={7,2,1};a==&a【0】;
然后还要知道指针的加法int*p;p=p+1;表示在该地址上加上一个int类型大小的地址。
所以你就可以这样把数组与指针结合int*p=a;
p==&a【0】;此时p就存的是a的首位地址
p=p+1;
p==&a【1】;p存的是第二个
当然你要明白加的是int类型的字节。若你是float指针指向int类型的数组,就会出现bug。
那么二维数组怎么办?
int a【2】【3】={{4,2},{1,8,9}};
int (*p)【3】=a;(这里用到了数组指针待会跟你讲)
此时p==&a【0】【0】;
这个时候要提醒一下你,数组名为第一个元素地址。
a==&a【0】==&(&a【0】【0】);
a+1==&a【0】+1==&a【1】==&&a【1】【0】;(地址加法,与p=p+1是相同的,相当于之前的非数组的a变成了p=&a+1)
这个懂了之后,就开始了结合。
*p==*a==*&a【0】==a【0】==&a【0】【0】;
p=p+1;
**p==**(a+1)==**(&a【0】+1))==**(&a【1】)==**(&&a【1】【0】)==*&a【1】【0】==a【1】【0】;
*(*p+1)==*(*(&a【1】)+1)==*(*(&&a【1】【0】)+1)==*(&a【1】【0】+1)==*&a【1】【1】==a【1】【1】;
哈哈,是不是有点乱,我写的时候也蒙一下。
其实这里可以只知道怎么算,如果不熟悉也没关系,等学了数据结构与算法后,你就基本可以掌握了。还有2级以上的指针也不是很常用。熟悉2级就足够了。
8、指针可以是数组,数组可以是指针,但两者本质还是不同的。
这句话可以这样说是因为int p【2】;*p=4;相当于p【0】=4;前面p是数组,但后面又变成了指针运算。
这是因为p=p+w是等价p【w】;所以指针可以与数组互通。但是注意两者还是右本质区别的。
数组始终是数组,指针始终是指针,指针可以做p=p+1,但是数组不可以这样,因为数组a=a+1,就会把整个数组都移动了。
9、进阶一下,数组指针和指针数组
数组指针就是 int(*p)【大小】,它是一个指向数组的指针,因为int*p只能用于一维的数组。
数组指针就是用来指向二维的数组。但注意p的大小一定是跟数组的最后一个【】里的数字相同。
这是因为p仍只是处理一维数组的,比如int a【2】【3】;int(*p)【3】=a;相当于p一个一个的处理a的2个拥有3个格子的数组。
这里也可以写成int**p,两者等价,是因为数组指针始终是一个指针。然后数组可以充当指针用。那么数组指针是指向数组的指针,也已翻译成指向指针的指针,所以可以用两个星号的指针。
指针数组,就是int*p【3】这个是一个存放指针的数组。若int**p【3】,那么就是存放两个星号类型指针的数组。
10、撑住很快结束了。这里要将数据和指针和函数的结合。
#include<stdio.h>
void uu(int a[]);
void uu2(int*p);
int* uu3(int*p);
void uu4(int**p);
int main(){
int b[4]={2,6,4,9};
int a=9;
int *p=&a;
uu(p);
uu2(b);
uu2(p);
int*p2=uu3(p);
int**p3=p2;
uu4(p3);
}
void uu(int a[]){
//a[2]=5;
//*(a+1)=2;
}
void uu2(int*p){
//p[2]=5;
//*(p+1)=2;
}
int* uu3(int*p){
return p;
}
void uu4(int**p){
**p=4;
}
uu和uu2都是指针与数组互通的应用。
指针和数组能够获取a,那么他就会生临时指针,但是还是拿到main里的a的地址,所以不会产生另外一个变量a。
uu3就是返回一个指针意思。p2=p;
uu4就是指针的指针使用。提一个小技巧,对于多个星号指针,你可以认为上锁与解锁。&就是上锁,*就是解锁。两个星表示这是一个开两个锁的。所以*p就是开一了一把锁,要在加一个*就可以解开所有锁,**p==a,所以你可以通过这是几个星号指针来判断需要多少个星号来访问变量或访问门。
11、最后一个了。常量指针
int a=10;const int*p=&a;那么p指向的那个a就不可以改变他的值。
int *const p2=&a;那么p2就只能指向a了,不能再指向其他变量。
忘了说*和【】,优先级是从右往左。也就是说先【】再*。
p++,和++p。++p先递增指针再做其他运算。p++,先做其他运算再递增指针。
指针可以指向字符窜。char*p=“”hello world“”;因为“hello world”=&h它就是首字母的地址。p获取了h的地址。
///
后面不知道要不要继续写c基础。其实这里已经把c的核心讲完了,剩下的结构体,枚举,多文件变成,重定向,文件操作,常用字符窜函数等内容。