指针:~用法、概念、含义、运算、指针和数组、指针和二维数组、字符指针和字符串、指针数组、多级指针、void指针、const修饰指针
目录
前言
指针:~用法、概念、含义、运算、指针和数组、指针和二维数组、字符指针和字符串、指针数组、多级指针、void指针、const修饰指针
大家可以通过代码理解学习
一、指针用法
C语言中使用指针可以
1. 程序简洁,紧凑,高效
2. 有效的表达复杂的数据结构
3. 动态分配内存
4. 得到多余一个的函数返回值
在计算机内存中,每一个字节单元,都有一个编号,称为地址;
编译或函数 调用时为其分配 内存单元
变量 是 对程序中数据存储空间的抽象
二、指针概念
在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,有时对地址,指针和指针变量不区分,统称指针。(地址==指针)
指针变量的说明
一般形式:
<存储类型><数据类型> * <指针变量名>
指针的英文名:pointer
例如:
char *p Name;
inta;
指针的存储类型是 指针变量本身存储类型
指针 说明时 指定的数据类型 不是 指针变量本身的数据类型,而是指针目标的数据类型,简 称为指针的数据类型。
指针在说明的同时,也可以被赋予初值,叫做指针的初始化。
一般形式是:
<存储类型><数据类型>*<指针变量名>=<地址量>;例如:
inta ,*pa=&a;
inta=1;
在上面的语句中,把变量a的地址 作为 初值赋予了 刚说明的int型指针pa。
用指针实现数字a,b的交换,可以通过以下代码理解学习
//用指针实现数字a,b的交换
#include <stdio.h>
void swap_3(int *p,int *q)
{
int t;
t=*p;
*p=*q;
*q=t;
}
main(void){
int a=3;
int b=5;
swap_3(&a,&b);
printf("a=%d,b=%d\n",a,b);
}
三、指针含义
指针 指向的 内存区域中的数据 称为指针的目标
如果它指向的区域是程序的一个变量的内存空间,则这个变量称为指针的目标变量,简称 为指针的目标。
引入指针要注意程序中的px 、*px 和 &px 三种表示方法的不同意义,设px为一个指针, 则:
px ,指针变量,它的内容是地址量
*px,指针所指向的对象,它的内容是数据
&px,指针变量占用的存储区域的地址,是一个常量
指针的赋值运算 指的是通过 赋值运算符 指针变量送一个地址值。
向一个指针变量赋值时,送的值必须是地址常量或指针变量,不能是普通的整数(除 了赋零以外)。
指针赋值运算常见的有以下几种形式:
1. 把一个普通变量的地址 赋给一个 具有相同数据类型的指针
doublex=15 ,*px ;
px=&x ;
2.把一个已有地址值 的 指针变量 赋给具有相同数据类型的另一个指针变量
floata,*px,*py;
px=&a;
py=px;
3.把一个数组的地址 赋给具有 相同数据类型的指针
int a[20], *pa;
pa = a; //等价于 pa = &a[0]
问题:什么是指针?
内存单元的地址 称为指针
指针有多少字节?
8
四、指针运算
1. 指针运算是以 指针变量 所存放的地址量 作为运算量而进行的运算。
2. 指针运算的实质 就是 地址的计算。
3. 指针运算的种类是有限的,它只能进行 赋值运算、算数运算 和 关系运算。
指针的算术运算见下表:
运算符 | 计算形式 | 意义 |
+ | px+n | 指针向地址大的方向移动n个数据 |
- | px-n | 指针向地址小的方向移动n个数据 |
++ | px++或++px | 指针向地址大的方向移动1个数据 |
-- | px--或--px | 指针向地址小的方向移动1个数据 |
· | px·py | 两个指针之间相隔数据元数的个数 |
//指针运算中的 算术运算
#include <stdio.h>
#include <stdlib.h>
main(void)
{
int a[5] = {1,2,3,4,5};
int *pa,*pb;
pa = a;
pb = &a[3]; //4
printf(" %p %d\n",pa,*pa);
printf(" %p %d\n",pb,*pb);
}
指针加减
注意:
1. 不同数据类型的两个指针 实行 加减法整数运算 是没有意义的
px+n表示的实际位置的地址量是:
(px)+sizeof(px的类型) * n
两个指针相减运算
px-py运算的结果是 两个指针指向的地址位置之间 相隔数据的个数。因此两个指针相减
不是两个指针持有的地址值 相减的结果。
两个指针相减的结果值不是地址量,而是一个整数值,表示两指针之间相隔数据的个数。
px++, ++px, px--, --px运算
指针的关系运算符
运算符 | 说明 | 例子 |
> | 大于 | px>py |
< | 小于 | px<py |
>= | 大于等于 | px>=py |
<= | 小于等于 | px<=py |
!= | 不等于 | px!=py |
== | 等于 | px==py |
两个指针之间的关系运算符 表示 它们指向的地址位置之间的关系,指向 地址大的指针 大于指向地址小的指针
指针与一般整数变量之间的关系运算 没有意义。
但可以和 零0 进行 等于或不等于 的关系 运算,判断 指针 是否为空。
五、指针和数组
在C语言中,数组的指针是指数组在内存中的起始地址,数组元素的地址是指数组元素在内存中的起始地址。
一维数组的数组名为一维数组的指针(起始地址)
例如:
doublex[8]; //x为数组的起始地址
设指针变量px的地址值等于数组指针x(即指针变量px指向数组的首元素),
则:x[i] 、(px+i)、(x+i) 和px[i]具有完全相同的功能:访问数组的第i+1个数组元素
int a[10], *p ; p=a;
p[i] <==> *(p+i)
注意:
1. 指针变量和数组在访问数组中元素时,一定条件下其使用方法具有相同的形式,因为 指针变量和数组名 都是地址量。
2. 但指针变量和数组的指针(或叫数组名)在本质上不同,指针变量是地址变量(可以++--),而数组的指针是地址常量(不可以++--)
例如:
inta[] = {1,2,3,4,5,6,7,8,9} , *p=a, i ; 数组元素地址的正确表达是:
(A). &(a+1) (B). a++ (C). &p (D). &p[i]
数组名是地址常量
p++ ,p-- (对)
a++, a-- (错)
a+1 ,*(a+2) (对)
可以通过以下代码理解学习
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a[] = {1,2,3,4,5,6,7,8,9,10};
int *p,i,n;
p = a;
n = sizeof(a)/sizeof(int);
for(i = 0;i<n;i++)
{
printf("%d %d\n",a[i],*(p+i));
}
printf("\n");
return 0;
}
可以通过以下代码理解学习
#include <stdio.h>
main(void)
{
int a[5]={5,6,7,8,9},sum=0,i;
int* p = a;
for (i=0;i<5;i++)
sum += *(p+i);
printf("%d\n",sum);
}
题目:数组反序存放
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a[] = {1,2,3,4,5,6,7,8,9,10};
int *p1,*p2,n,t; //t 是临时存放量
n = sizeof(a)/sizeof(int); //取个数
p1 = a; //数组头
p2 = &a[n-1]; //数组尾
while(p1 < p2)
{
t = *p1;
*p1 = *p2;
*p2 = t;
p1++;
p2--;
}
for(t=0;t<n;t++)
{
printf("%d \n",a[t]);
}
return 0;
}
六、指针和二维数组
多维数组就是具有 两个或两个以上下标的数组
在C语言中,二维数组的元素连续存储,按行优先存
题目:一级指针遍历二维数组
可以通过以下代码理解学习 [有个小失误]
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a[3][2] = {{1,2},{3,4},{5,6}};
int *p1,n,i;
n = sizeof(a)/sizeof(int); //取个数
p1 = a[0];
printf("%p %p \n",a,a+1);
printf("%p %p \n",p1,p1+1);
for(i=0;i<n;i++)
{
printf("%d \n",*(p1+i));
}
return 0;
}
可以把二维数组看作由多个一维数组组成。
比如ina a[3][3] ,含有三个元素,a[0],a[1],a[2] 元素a[0],a[1],a[2]都是一维数组名
二维数组名 代表数组的起始地址,数组名加1,是移动一行元素。因此,二维数组名常被 称为行地址。
行指针(数组指针)
存储行地址的指针变量,叫做 行指针变量,形式如下:
<存储类型> <数据类型> (*<指针变量名>) { 表达式n };例如:
inta[2][3] ; int (*p)[3];
方括号中的常量表达式 表示指针加1,移动几个数据。
当用 行指针 操作 二维数组时,表达式一般写成 1行的元素个数,即列数。
题目:使用行指针表示二维数组的某个元素
可以通过以下代码理解学习
//使用行指针表示二维数组的某个元素
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[3][2] = {{1,2},{3,4},{5,6}};
int (*p)[2],i,j;
p =a;
printf("%p %p \n",a,a+1);
printf("%p %p \n",p,p+1);
//printf("%d %d %d %d\n",a[1][1],p[1][1],*(*(a+1)+1),*(*(p+1)+1));
for(i=0;i<3;i++)
{
for(j=0;j<2;j++)
{
printf("%d %d %d %d\n",a[i][j],p[i][j],*(*(a+i)+j),*(*(p+i)+j));
}
printf(" \n");
}
return 0;
}
七、字符指针和字符串
C语言通过使用 字符数组 来处理字符串
通常,我们把char数据类型的指针变量称为 字符指针变量。
字符指针变量与字符有着 密切关系,他也被用来 处理字符串。
初始化字符指针 是把 内存中字符串的首地址 赋予指针,并不是把 该字符串复制到指针中。
charstr[] ="Hello World";
char*p=str;
可以通过以下代码理解学习
//初始化字符指针 是把 内存中字符串的首地址 赋予指针,并不是把 该字符串复制到指针中。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
char ch1[] = "hello world";
char ch2[] = "hello world";
char *p;
p = ch1;
if(isalpha(*p))
{
if(isupper(*p))
{
*p = tolower(*p);
}
else
{
*p = toupper(*p);
}
}
printf("%s %p \n",p,&p);
printf("%s %p \n",ch1,ch1);
p = ch2;
printf("%s %p \n",ch2,ch2);
return 0;
}
在C语言编程中,当一个字符指针 指向一个字符串常量时,不能修改指针指向的对象的值
char*p="Hello World";
*p='h';
题目:不使用任何 字符串函数,实现字符串函数连接功能
可以通过以下代码理解学习
//题目:不使用任何 字符串函数,实现字符串函数连接功能
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch[100] = "Welcome";
char *p = " hello world",*a;
int i = 0;
a = p;
while(*(ch+i) |= '\0') //找到字符串结束的位置
{
i++;
}
while(*p != '\0') //不等于结束符的时候
{
*(ch+i) = *p;
p++;
i++;
}
*(ch+i) = *p; //加上字符串结束符,完成拼接的功能
p = a;
puts(ch);
puts(p);
return 0;
}
八、指针数组
所谓 指针数组 是指由 若干个具有相同存储类型和数据类型的指针变量构成的集合
指针数组的一般说明形式:
<存储类型 > <数据类型> *<指针数组名> [<大小>]
指针数组名 表示 该指针数组的起始地址 声明一个指针数组
double*pa2[2] , a[2][3];
可以存放在静态存储区的 (1.全局变量 2.static局部变量 3.字符串变量)
把一维数组a[0] 和 a[1]的首地址分别赋予指针变量数组的数组元数pa[0] 和pa[1];
pa[0] =a[0]; //等价于pa[0] = &a[0][0] pa[1] =a[1]; //等价于pa[1] = &a[1][0]
此时pa[0]指向了一维数组a[0]的第一个元素,而pa[1]指向了一维数组a[1]的第一个元素。
题目:使用指针数组处理二维数组,求出二维数组所有元素的和。
可以通过以下代码理解学习
//题目:使用指针数组处理二维数组,求出二维数组所有元素的和。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p[2];
int a[2][3] = {{1,3,5},{2,4,6}};
int i,j,sum;
p[0] = a[0];
p[1] = a[1];
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d \n",*(p[i]+j));
sum = sum + *(p[i]+j);
}
printf("\n");
}
printf("%d \n",sum);
return 0;
}
九、多级指针
多级指针的定义:把一个指向指针变量的指针变量,称为指针变量
对于指向处理数据的指针变量称为一级指针变量,简称一级指针。
而把指向一级指针变量的指针变量称为二级指针变量,简称二级指针。
二级指针变量的说明形式如下:
<存储类型> <数据类型> **<指针名> ;
多级指针的运算
1. 指针变量+1,是向地址大的方向移动一个目标数据。同理,多级指针运算也是以其目 标变量为单位进行偏移
比如, int* *p; p+1 移动一个int * 变量所占的内存空间。
可以通过以下代码学习理解
//多级指针
#include <stdio.h>
#include <stdlib.h>
int main()
{
int m = 10;
int *p;
int* *q;
p = &m;
q = &p;
printf("%p %p \n",p,&m);
printf("%p %p \n",q,q+1);
return 0;
}
多级指针和指针数组
指针数组也可也用另外一个指针来处理。
例如: 有一个 一维字符指针数组 ps[5]
char*ps[5] = {"Beijing","Fuzhou","Xiamen","XiAn","ShangHai"};
可以通过以下代码理解学习
//多级指针和指针数组
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *p[3]={"beijing","xiamen","duzhou"};
int n,i; //i 用于循环
char* *q;
n = sizeof(p) / sizeof(char*);//n 取个数
q = p;
while(i<n)
{
printf("%s %s \n",p[i],*(q+i));
i++;
}
// printf("%d \n",n);
//printf("%s %s \n",p[0],*q);
return 0;
}
十、void指针
void指针是一种 不确定数据类型 的指针变量,它可以通过 强转类型转换 让该变量指向任何数据类型的变量。
一般形式为: void *<指针变量名称>;
对于void指针,在 没有 强制转换类型之前,不能 进行 任何指针的算术运算。
强制转换类型 可以通过以下代码理解学习
//强制转换
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a = 10;
void *p;
p = &a;
printf("%d %d \n",a,*(int *)p); //(int *)强制转换
return 0;
}
题目:使用void指针遍历一维数组
可以通过以下代码理解学习
//题目:使用void指针遍历一维数组
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[5] ={1,2,3,4,5};
int n,i,*q;
void *p;
p = a;
q = (int *)p;
n = sizeof(a) / sizeof(int*);//n 取个数
for(i = 0;i<n;i++)
{
printf("%d ",a[i]);
printf("%d ",*((int *)p+i));
printf("%d\n",*(q+i));
}
return 0;
}
十一、const修饰指针 (重难点)
常量化变量 的值
一般说明形式如下:
const<数据类型>变量名=[<表达式>];
常量化变量 是 为了使得变量的值不能修改
变量有 const修饰时,若 想用指针间接访问变量,指针 也要有 const修饰。
const放在指针声明什么位置呢?
回答:开头
常量化指针 目标表达式
一般说明形式如下:
const<数据类型> * <指针变量名称> [=<指针运算表达式>];
常量化指针目标 限制 通过 指针改变其目标的数值 , 但是指针变量存储的地址可以修改
可以通过以下代码理解学习
常量化指针 变量 及其 目标表达式
一般说明形式如下:
const<数据类型> * const<指针变量名> = <指针运算表达式>
常量化指针目标 是 限制 通过 指针改变其目标的数值 , 但是<指针变量>存储的地址值可以修改
常量化指针变量
一般说明形式
<数据类型> * const<指针变量名称> [<指针运算表达式>]
使得<指针变量>存储的地址值不能修改。但可以通过 *<指针变量名称>可以修改所指向变量的数值。
可以通过以下代码理解学习
总结
指针:~用法、概念、含义、运算、指针和数组、指针和二维数组、字符指针和字符串、指针数组、多级指针、void指针、const修饰指针
大家可以通过代码理解学习