文章目录
Linux-C P7 指针
指针涉及的内容很多,通过思维导图也能够了解到
从开始的指针的基础和运算到多级指针
从数组指针和指针数组来了解数组与指针之间的关系
后面还会讲到const指针、void指针和字符指针
指针基础及运算
指针概念
什么是指针?
指针就是用来存储地址的变量,可以使程序简洁、紧凑、高效;有效地表示复杂的数据结构;实现动态分配内存;得到多于一个的函数返回值
地址又是什么?
说到地址,我们可以形象的理解一下,你要找一个人,需要先知道他家的地址在哪,然后才有可能在他家找到他,所以地址对于内存也是一样,通过地址,我们可以找到对应地址里的内容
指针变量
指针变量
专门用来存放地址的变量
指针变量的定义
为了使用指针变量需要先对指针变量进行定义
一般形式
数据类型 *变量名;
int *p;
这里定义了一个指针p,且返回的是整型(int)
指针变量的赋值
定义完之后,需要给指针变量赋值
指针变量的赋值有两种,接下来一一介绍
方式一
int *p;
p = &i;
方式二
int * p = &i;
关于指针的基本使用,通过下面的例子来了解一下
举个栗子
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 50,y = 100;
int *p1;
p1 = &x;
int *p2 = &y;
printf("x = %d,*p1 = %d,&x = %p,p1 = %p,&p1 = %p\n",x,*p1,&x,p1,&p1);
printf("y = %d,*p2 = %d,&y = %p,p2 = %p,&p2 = %p\n",y,*p2,&y,p2,&p2);
return 0;
}
这里分别用了两种方法来赋值指针,然后分别输出两种赋值之后的内容和地址信息
可以看到x = *p1 ,&x = p1,&p1 =0xbfc0c2b8
具体的原因后面会给大家揭晓
关于&和*
前面的栗子里,分别输出了x和&x,p1、*p和&p,这些都代表什么呢?
为什么x与*p1的结果相同,&x和p1结果相同呢?
首先是
&——取地址运算符,获取变量对应的地址
*——指针运算符,获取地址里存储的变量
下面通过图来说明p,*p和&p之间的关系
p——指针变量,内容是地址量
*p——指针所指向的对象,内容是数据
&p——指针变量占用的存储区域的地址,即存放地址的地址
p1是变量x的地址
*p1是指针指向的内容
&p1是存放变量x的地址的地址
指针运算
关于指针的运算,指针能进行算术运算、关系运算和赋值运算,除了这些还有一些指针表达式
算术运算
运算符 | 计算式 | 意义 |
---|---|---|
+ | p+n | 指针向地址大的方向移动n个数据 |
- | p-n | 指针向地址小的方向移动n个数据 |
++ | p++或++p | 指针向地址大的方向移动1个数据 |
– | p–或--p | 指针向地址小的方向移动1个数据 |
- | p-q | 两个指针之间相居左隔数据元素的个数 |
举个栗子
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 50;
int *p,*q;
p = &x;
q = p-2;
printf("p = %p\n",p);
printf("p+2 = %p,p-2 = %p\n",p+2,p-2);
printf("p++ = %p,p-- = %p\n",p++,p--);
printf("p-q = %p\n",p-q);
return 0;
}
关系运算
运算符 | 说明 | 计算式 |
---|---|---|
> | 大于 | p>q |
< | 小于 | p<q |
>= | 大于等于 | p>=q |
<= | 小于等于 | p<=q |
!= | 不等于 | p!=q |
== | 等于 | p==q |
举个栗子
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char s[]="HelloWorld";
char *p = NULL,*q = NULL,t;
printf("%s\n",s);
p = s;
q = s + strlen(s) - 1;
while(p < q){
t = *p;
*p = *q;
*q = t;
p++;
q--;
}
printf("%s\n",s);
return 0;
}
数组指针
指针与一维数组
什么是数组指针?
数组指针,就是指向数组的指针,指针名就是指向数组的首地址
int a[10];
int *p;
p = a;
这里p+1指的是加一个数据类型的长度,而不是1bit
等价关系
数组名 + i --> 数组名[i]
举个栗子
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int *p;
int i,n;
p = a;
n = sizeof(a)/sizeof(int);
for(i = 0;i < n;i++){
printf("a[%d] = %d,*(p + %d) = %d\n",i,a[i],i,*(p+i));
}
return 0;
}
常见等价操作
指针操作 | 数组操作 | 说明 |
---|---|---|
array | &array[0] | 数组首地址 |
*array | array[0] | 数组的首元素 |
array + i | &array[i] | 数组第i个元素的地址 |
*(array + i) | array[i] | 数组的第i个元素 |
*array + b | array[0]+b | 数组首元素的值加b |
*(array + i) + b | array[i]+b | 数组第i个元素的值加b |
*array++(当前指向第i个元素) | array[i++] | 先取得第i个元素的值,i再加1 |
*++array(当前指向第i个元素) | array[++i] | 先将i加1,再取得第i个元素的值 |
*array–(当前指向第i个元素) | array[i–] | 先取得第i个元素的值,i再减1 |
*–array(当前指向第i个元素) | array[–i] | 先将i减1,再取得第i个元素的值 |
指针与多维数组
二维数组指针
介绍完一维数组指针,平时还会用到二维数组指针
二维数组指针的一般形式
<数据类型> (*<指针变量名>)[表达式];
举个栗子
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a[3][3] = {{0,1,2},{3,4,5},{6,7,8}};
int i,j,m,n;
int (*p)[3];
p = a;
m = sizeof(a)/sizeof(a[0]);
n = sizeof(a[0])/sizeof(int);
for(i = 0;i < m;i++){
for(j = 0;j < n;j++){
printf("%d %d %d ",a[i][j],*(*(a+i)+j),*(a[i]+j));
printf("%d %d %d\n",p[i][j],*(*(p+i)+j),*(p[i]+j));
}
printf("\n");
}
return 0;
}
多级指针
多级指针定义
多级指针变量,一个指向指针的指针变量
对于指向处理数据的指针变量称为以及指针
而指向向一级指针变量的指针变量称为二级指针
二级指针变量的基本形式
<数据类型> **<指针名>
多级指针运算
关于多级指针运算具体的运算原理,先来看个例子,再剖析他
举个栗子
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 50;
int *p;
int **q;
p = &x;
q = &p;
printf("x = %d,&x = %p\n",x,&x);
printf("p = %p,&p = %p,*p = %d\n",p,&p,*p);
printf("q = %p,&q = %p,*q = %p,**q = %d\n",q,&q,*q,**q);
return 0;
}
指针数组
指针数组定义
指针数组是一个数组,每个数组元素存放一个指针变量
指针变量数组的一般说明形式
<存储类型> <数据类型> *<指针变量数组名>[<大小>]
指针数组运算
举个栗子
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 50,y = 100;
int *p[2];
p[0] = &x;
p[1] = &y;
printf("x = %d,&x = %p\n",x,&x);
printf("p[0] = %p,*p[0] = %d,&p[0] = %p\n",p[0],*p[0],&p[0]);
printf("y = %d,&y = %p\n",y,&y);
printf("p[1] = %p,*p[1] = %d,&p[1] = %p\n",p[1],*p[1],&p[1]);
return 0;
}
const和void
const指针
用const修饰指针变量,会使得指针变量常量化
const指针用三种表示形式
常量化指针目标表达式
const <数据类型> *<指针变量名称>[=<指针运算表达式>]
使得指针不能修改指向变量的值
常量化指针变量
<数据类型> *const<指针变量名称>[=<指针运算表达式>];
使得指针不可以修改其地址
常量化指针变量及其目标表达式
const <数据类型> *const<指针变量名>=[<指针运算表达式>];
使得指针既不能修改指向变量的值,也不可以修改其地址
举个栗子
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 50,y = 100;
const int *p1;
int *const p2;
p1 = &x;
printf("x = %d,&x = %p,*p1 = %d,p1 = %p\n",x,&x,*p1,p1);
x++;
printf("x = %d,&x = %p,*p1 = %d,p1 = %p\n",x,&x,*p1,p1);
p1 = &y;
printf("y = %d,&y = %p,*p1 = %d,p1 = %p\n",y,&y,*p1,p1);
*p2 = &x;
printf("x = %d,&x = %p,*p2 = %d,p2 = %p\n",x,&x,*p2,p2);
x++;
printf("x = %d,&x = %p,*p2 = %d,p2 = %p\n",x,&x,*p2,p2);
*p2 = &y;
printf("y = %d,&y = %p,*p2 = %d,p2 = %p\n",y,&y,*p2,p2);
return 0;
}
void指针
void型的指针变量是一种不确定数据类型的指针变量
定义变量的时候,通过类型来决定该变量所占的内存空间
一般形式
void *<指针变量名称>
null指针
如果一个指针不指向任何数据,我们就称之为空指针,用 **NULL **表示
NULL ((void *)0)
字符指针
字符串
通常借助于字符数组来存储字符串,字符指针可以存储字符串的起始地址,即指针指向字符串第一个字符,这样,我们可以用指针来处理字符串
字符指针数组
若数组中存储了若干个字符串的地址,则这样的数组叫作字符指针数组
举个栗子
#include <stdio.h>
#include <string.h>
int main(int argc, const char *argv[])
{
char s1[] = "Welcome";
char s2[] = "to";
char s3[] = "CagePan";
char* a1[3] = {s1,s2,s3};
char *a2[3] = {"Welcome","to","CagePan"};
char **p;
int i;
p = a1;
printf("array1:%s %s %s\n",a1[0],a1[1],a1[2]);
for(i = 0;i < sizeof(a2)/sizeof(char *);i++){
printf("%s ",*(p+i));
}
printf("\n");
p = a2;
printf("array2:%s %s %s\n",a2[0],a2[1],a2[2]);
for(i = 0;i < sizeof(a2)/sizeof(char *);i++){
printf("%s ",*(p+i));
}
printf("\n");
return 0;
}