第一篇博客周报记录——多维数组和指针
这是我的第一篇博客,说实话平时记录学习成果都是用笔写本子上,不过既然实验室要求了,那就试试写博客吧。这周主要进度是先把桶排,冒泡排,快排,队列了解了一下,再就是多维数组和指针这一块,附带把形参和实参再次仔细理解了一下。第一篇就先说一下多维数组和指针吧。
高中时玩过比较长一段时间的arduino,所以为此自学过一点点c语言,当时就听说指针是c语言的精髓,是C/C++语言的一种特色,体现了C/C++语言的自由性质,这周算是系统的去了解了一下指针,在此记录一下目前我对指针和数组的理解(后续深入了解后还要再更新吧)。
相信很多c语言初学者在学习scanf函数的时候都会犯这样一个错误:
如图所示我们会发现程序没有如愿输出a和b的值,查了scanf用法后发现应该是scanf("%d,&a");&a中的&是寻址操作符,&a表示对象a在内存中的地址,我们是用scanf把值赋给a所在的地址,地址是房子,而数据是住在房子里面的人
那就回到我们今天的主角——指针上了,先看看书上是怎么定义的叭:
指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
简单地说:指针是一个值为内存地址的变量,int类型变量的值是整数,char类型变量的值是字符,而指针变量指向的是地址。这样我们就很容易猜到指针的第一个作用——到那个房子去找住在房子里的人,或者房子依然在那,换个业主。在这放一个接下来会用到的关键比喻,指针是钥匙
简单介绍一下指针变量定义的格式:
类型标识符 *变量名; 如:int *point;
(注意:在定义int point;的时候 ,加粗部分的不是取值符,而是修饰point是一个指针变量)如何确定point指向什么类型的变量呢,需要进行下一步:看非加粗部分,int则表示point指向int类型变量或保存int类型变量的地址。
#include<stdio.h>
int main()
{
int *p;
int a=2;
p=&a; //p=a错误,此处p就是个存整数型变量的地址的量
printf("%d %d %d %d",p,*p,a,&a);
}
输出结果是6684180 2 2 6684180,可见p存了a的地址&a。
为什么我们要盯着地址不放呢,因为不人为改变的话变量的地址是确定的,就像电脑里6684180这个地址只有一个,但是2这个数据可以有千千万,我们找变量是找这个住在房子(地址)里面的人,而不是找他的信息拷贝或者刚刚好和他很像的人。
于是我打了一个交换数值的程序
#include <stdio.h>
void swap(int x,int y)
{
int temp;
temp=x;
x=y;
y=temp;
}
int main()
{
int a,b;
scanf("%d,%d",&a,&b);
if(a<b) swap(a,b);
printf("\n%d,%d\n",a,b);
}
结果我们发现程序没有报错,但是运行结果没有变化,为什么swap这个函数没有什么用呢,原因涉及到开头我们提及到的两个概念——形参和实参,大概介绍一下(我的简单理解):
比如你定义一个函数void add(int a, int b),这里的a和b就是形参
当你进行函数调用的时候,add(1, 2),这里的1和2就是实参。
形参顾名思义,一个形式,它没有具体值,它是一个概念,代表着这里有这种类型的值存在,
让我们创建我们这篇文章的一个核心比喻——
宾馆
程序是一个有很多个房管上班的大宾馆,房管可以用指纹查询用户的资料,函数就是一个房管,在条件允许的情况下它可以改变住户。形参就像是房管的指纹,它只对这个房管有用(在整个函数体内都可以使用),与别的房管无瓜(离开该函数则不能使用),不用来解锁时它啥用也没有,就是个指纹(形参变量只有在被调用时才分配内存单元),它只是一个模板,一个得到并记录密码(实参)的模板。
实参顾名思义,实际存在。住房的比喻中它是身份。实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。int a=2;好了,现在a就是个实参,它有实际量。
实参出现在主调函数中,进入被调函数后,实参变量也不能使用。所以我们再看上面的代码swap(a,b)是实参,它把a的数据给了x,把b的数据给了y,注意,x,y此时就是指纹作为信息的拷贝,就像房管拿到了住户的信息拷贝,他可以随意篡改在他记下的信息,但这对住户真实信息没有影响
运行后我们发现,x,y的值没有返回给a,b,就像是我们的房管(函数)知道里面住的谁,但并不能访问它。我们的房管的确得到了他所要去找的住户资料,但是可惜他好像不知道怎么才能见到住户(参数)本人。
于是我写了下面的代码,或者说,我给了房管他需要的钥匙,
#include <stdio.h>
void swap(int *x,int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
int main()
{
int a,b;
scanf("%d,%d",&a,&b);
if(a<b) swap(&a,&b);
printf("\n%d,%d\n",a,b);
}
指针像是钥匙,我们把a和b的地址给了房管,房管找到了a和b,并用钥匙打开了房门,成功影响了a和b,因为无论实参的数值怎么变,它的地址是不会随之改变的。我们通过地址找到参数(你跑的了和尚跑的了庙吗),在房间内改变它而不是光在信息表上改它的信息拷贝,所以返回后a和b的值真正得到了交换。
ps:其中我遇到了一个小问题,scanf输入数值的时候总是发现b有问题,问了学长才发现是因为我的逗号默认的是中文输入法的逗号,这对输入会造成非常大的影响。
用比喻简单介绍了我目前所理解的指针,接下来我们讲讲数组
数组由数据类型相同的一系列元素组成(要是想问我想存不同元素怎么办,别问,问就是结构体,这个后续总结)。我刚见到数组的时候心里想到的就是,怎么创造,既然是集合,那怎么得知大小,如何修改,如何提取?
一维数组不想总结了,就写几个当时认为的重点吧
1.定义数组时下标数不允许包含变量(下面是个会报错的错误示范)
#include<stdio.h>
int main ()
{ int a=4;
int q[a]={1,2,3,4,5}; //不能有a这种变量
int q[5]={a,a,a,a,a}; //这样是可以的
printf("%d",q[a]);//这样也行
}
2.使用数值型数组时,不可以一次引用整个数组,只能逐个引用元素
3.C语言不允许直接把一个数组整个赋给另一个数组
4.数组名是该数组首元素的地址(多维数组同样适用!)
C 语言中的多维数组(multidimensional array)其实就是元素为数组的数组。n 维数组的元素是 n-1 维数组。例如,二维数组的每个元素都是一维数组,一维数组的元素当然就不是数组了
多维数组声明时,每个维度用一对方括号来表示:
char screen[10][40][80]; // 一个三维数组
下面是两个关于二维数组找出里面最大数的代码
#include<stdio.h>
int main()
{
int x,y;
int s[3][2]={0};
for(x=0;x<3;x++)
{
for(y=0;y<2;y++)
{
printf("请输入s[%d][%d]:",x,y);
scanf("%d",&s[x][y]);
}
}
int t=*(*s);
for(int a=1;a<(x*y);a++)
{
if(t<*(*s+a)){
t=*(*s+a); }
}
printf("最大的是%d",t);
getchar(); getchar();
}
#include<stdio.h>
void max(int u[3][2],int *t);
int main()
{
int x,y,M;
int s[3][2]={0};
for(x=0;x<3;x++)
{
for(y=0;y<2;y++)
{
printf("请输入s[%d][%d]:",x,y);
scanf("%d",&s[x][y]);
}
}
printf("%d %d",s,&s[0][0]);//可见s==&s[0][0]
max(s,&M); //s表示这个s[3][2]的地址
printf("最大的是%d",M);
getchar();
}
void max(int u[3][2],int *t){
*t=*(*u);
for(int a=1;a<(3*2);a++)//在这里我选择了直接通过地址来找数据,因为多维数组也是链性储存,这样减免了for循环的嵌套
{
if(*t<*(*u+a)){
*t=*(*u+a); }
printf("此时最大的是%d\n",*t);
}
}
//报错是因为int *a[3]表示一个一维数组,数组的数据类型为整型指针(int*),数组的大小为3,这是因为[]的优先级高于*的优先级
然后再补充一下关于数组的指针的一个点
int max[3][5];
int p;
p=*(*(max+1)+5);
值得一提的是,这里max的类型是“指向包含10个整型元素的数组的指针”,它指向第一个子数组,表达式max+1也是“指向包含10个整型元素的数组的指针”,但它指向max的另一行,那么问题来了——*( *(max+1)+5)是指的什么?
这里的*( (max+1)+5)我们可以拆开来分析,(max+1)实际上等于max[1]那max[1]是什么呢?它是一个地址!(因为这是个二维数组),所以*( *(max+1)+5)中的
*(max+1)+5其实是max[1][5],数组的指针运算就是存储空间往后推,因为它是连续的,不过要是+11那就是max[2][1]了。
剩下的以后补充吧,慢慢来