1.段错误
当我们将代码运行的时候,会看到“段错误”这三个字,令我们很是头疼,因为没有明确标出哪里错了,所以我们盘点一下段错误的几个类型。
1.1 野指针
1. 定义指针之后,没有将它指向明确的地址。
int *p;
scanf("%d",p);
2. 指针p被free(释放 )之后,没有置NULL,会让人以为p是合法指针,然后拿它来用
解决方法:p = NULL
1.2 内存泄漏,非法空间使用
int *p = (int *)malloc(sizeof(100));
p = (int *)malloc(sizeof(200));
例如,我们先让指针p指向一块地址空间,然后让它指向另外一块,此时,第一次开辟的空间虽然存在,但是我们已经失去了他的地址,没有及时释放,就成为了垃圾内存,会占用资源
2. 二级指针
一级指针:存储变量的地址
二级指针:存储一级指针的地址
格式:存储类型 数据类型 **指针变量;
int **p;
3. 指针与数组
对于数组的访问:
1. 直接访问:按变量的地址存取变量的值(通过数组名访问)
2. 间接访问:通过存放变量地址的变量去访问变量(通过指针访问)
前言小提示:在数组中,数组名表示的是首地址,指针记录的也是地址,他们有什么关系呢,或者说,可不可以用指针替换数组名呢,我们接下来看看。
3.1 指针与一维数组
直接访问: int a[3] = {1,2,3};
地址 | 元素 | 值 | ||
a | &a[0] | 1 | a[0] | *a |
a+1 | &a[1] | 2 | a[1] | *(a+1) |
a+2 | &a[2] | 3 | a[2] | *(a+2) |
间接访问:int *p = a;
地址 | 元素 | 值 | ||
p | &p[0] | 1 | p[0] | *p |
p+1 | &p[1] | 2 | p[1] | *(p+1) |
p+2 | &p[2] | 3 | p[2] | *(p+2) |
通过两个表格,我们可以看到,他们的格式都是一样的,只不过就是数组名和指针的区别,所以,我们就可以直接用指针替换数组名。
注意:a和p本质不同 a:地址常量 p:变量 a++不可以 p++可以
访问数组的元素a[i]的值:直接:a[i] *(a+i)
间接:p[i] *(p+i)
访问数组的元素a[i]的地址:直接:&a[i] a+i
间接:&p[i] p+i
3.2 指针与二维数组
我们之前学习了二维数组的地址,他的数组名+1是指向了第二行,而不是第一行第二个元素,那么,我们怎么要才能让他指向其他列的元素呢?
在二维数组中,我们可以通过‘ * ’来降级,也就是说,第一行的地址,变成了第一行第一列的地址,这样,在数组名+1的时候,就不是指向第二行的地址,而是第一行第二列的地址。
a:第一行的首地址*a:第一行第一列的首地址第一行第二列的首地址:(*a)+1
直接访问:int arr[2][2] = {1,2,3,4};
地址 | 元素 | 值 | ||||
a[0] | a / *a | &a[0][0] | 1 | a[0][0] | **a | *a[0] |
a[0]+1 | *a+1 | &a[0][1] | 2 | a[0][1] | *(*a+1) | *(a[0]+1) |
a[1] | a+1/ *(a+1) | &a[1][0] | 3 | a[1][0] | *(*(a+1)) | *a[1] |
a[1]+1 | *(a+1)+1 | &a[1][1] | 4 | a[1][1] | *(*(a+1)+1) | *(a[1]+1) |
间接访问: 在这里,我们要学习一个 数组指针,也就是行指针
定义:本质是指针 指向数组(行指针)
格式:存储类型 数据类型 (*指针变量) [列数]
int a[2][3]={1,2,4,4,5,6};
int (*p)[3]=a;
a+1 p+1:移动一整行 移动三个数据单位
我们可以看到,p与a的作用是一样的,同样是行地址,根据3.1我们学到的,我们是不是直接可以将他们进行替换
地址 | 元素 | 值 | ||||
p[0] | p / *p | &p[0][0] | 1 | p[0][0] | **p | *p[0] |
p[0]+1 | *p+1 | &p[0][1] | 2 | p[0][1] | *(*p+1) | *(p[0]+1) |
p[1] | p+1/ *(p+1) | &p[1][0] | 3 | p[1][0] | *(*(p+1)) | *p[1] |
p[1]+1 | *(p+1)+1 | &p[1][1] | 4 | p[1][1] | *(*(p+1)+1) | *(p[1]+1) |
访问a[i][j]的值:直接:a[i][j] *(*(a+i)+j) *(a[i]+j)
间接:p[i][j] *(*(p+i)+j) *(p[i]+j)
访问a[i][j]的地址:直接:&a[i][j] *(a+i)+j a[i]+j
间接:&p[i][j] *(p+i)+j p[i]+j
3.3 指针数组
定义:本质是数组,数组中存放的都是指针
定义格式:存储类型 数据类型 * 指针变量名 [元素的个数];
int *p[3];
这个数组中,存放的元素是指针,当我们用数组名来表示的时候,相当于用二级指针去指向,所以,我们只要学会二级指针,指针,普通变量之间的关系,这个指针数组就比较简单了。
**q-->*p-->a,这是他们的指向,接下来我们用几个等式来看看:
1. q = &p; 2. *q = p; 3. p = &a; 4. *p = a;
将3代入到2中,*q = &a
到这里,我们不难看出,再+‘*’,就可以用二级指针q取到a的值
**q = a;
今天的学习就到这里啦,继续努力呀!
今天留一个小练习,比较简单
已知字符数组a[10]和b[10]中元素的值递增有序,用指针实现将两个数组中元素按照递增顺序输出。
如:char a[10]=”acdgjmno” ; char b[10]=”befhil”;->”abcdefghijlmno”
#include<stdio.h>
int main(int argc, char const *argv[])
{
char a[20],b[20];//a=acdgjmno;b=befhil;
gets(a); //在终端输入两个字符串
gets(b);
char *p = a;
char *q = b;
while (*p != '\0' && *q != '\0')//两个字符串都不等于结束符的时候进行循环
{
if(*p > *q) // 比较大小,将小的进行输出,并将指针向后移
{
printf("%c",*q);
q++;
}
else
{
printf("%c",*p);
p++;
}
}
if(*p == '\0')//在结束循环时,肯定有一个字符串到结束符了,另一个则没有,那么直接进行输出
puts(q);
if(*q == '\0')
puts(p);
return 0;
}
欢迎大家指正!!!!