变量的内存地址与指针
指针变量
本质:指针是已定义的数据变量的存放地址;该地址就是访问该变量的内存地址;
指针变量是用来存放数据变量地址的内存变量。通过取地址运算的赋值操作后,将使该指针变量指向那个被取出地址的数据变量;
指针变量一般即称:指针;
指针的内容:就是各种已定义数据类型操作对象的内存地址;
// 比较直接访问与间接访问数据变量的 操作方式
// 比较直接访问与间接访问数据变量的 操作方式
#include "stdio.h"
void main(){
int i=20;
int m,n;
int* i_pointer =&i;
m=i+6; //直接访问变量i数据值
n=*i_pointer+3; // 间接访问i,通过指针
i_pointer=&m; // 指针指向m变量
printf("m=%d \nn=%d \n",*i_pointer,n); // m 是通过间接访问,n 直接访问
}
指针就是存放如下内存地址的变量;变量名相当于是引用(取外号小名);
指针变量的赋值
指针变量的赋值:只能是赋予已定义变量的地址值 ,而不能赋予任何其他数据;
C语言提供了地址运算符“&”来表示和执行变量地址的运算;
变量地址运算的一般形式为: &变量名; Eg: &number 为:运算结果为变量number的地址;
注意:像符号 “*”和“&”都具有多义性,即在不同的环境下表示的语法含义不同
指针变量定义初始化操作:
int number;
int* p=&number;
等价于:
int number;
int* p;
p=&number;
指针变量运算符及运算
地址变量运算符: “&”:取地址运算符 ;“*”:变量值存取运算符;
可能形式:&*pointer 运算,等效于 &(pointer):结果还是pointer对应的内存地址;
(&x)运算–等效于(&x):结果是对应的x变量值;
(pointer)++,相当于x++;
有pointer++,等效于(pointer++);
// 简单小例子
// 指针变量运算符及运算
#include "stdio.h"
void main(){
int a=10,b=20;
int* pointer =&a; // pointer指向a
a=*pointer+5;
pointer=&b; //pointer指向b;
b=*pointer +a;
printf("a is %d,b is %d \n",a,*pointer);
printf("b address is %d \n",pointer);
}
指针变量运算
Eg1:
int x;
int* px=&x;
int* pb;
pb=px;
Eg2:
int x[5],*px;
px=x;数组名就是首地址;
Eg3:
char *pc;
pc=“c language” // 即为把字符串的首地址赋值给pc;
2、加减运算符
指针的加减运算符对于单个变量没有意义,主要是对于指向数组或链表的指针变量;加减运算符运算按数据类型长度为单位;
int x[5];
int* px;
px=x; // px指向数组x的首地址,即指向数组元素x[0]的地址
px=px+2; // px指向x[2]的地址,即px的值为&x[2]的地址
3、空指针运算
空指针p=NULL表示指针变量p不指向任何数据变量;
if(p=NULL) …
注意:空指针与指针未赋值是不同的;空指针p=NULL,等价于看做值为NULL,不指向任何变量的指针变量,但是未赋值的指针,无指向且地址值不定,有可能随机指向而破坏系统;所以指针一旦定义必须被赋值初始化,使其有所指向
指针变量作为函数参数
指针变量作为函数参数,是将变量的地址传到另一函数参数,是对变量数据的实际操作,因为传递的是指向数据变量的地址,所有可以操作实际变量的数据值,但是本身 实际指针参数和形式指针参数没有关系,还是属于单向传递;
// 编写程序,任意输入两个数,通过函数调用来交换两个变量值;
// 指针变量作为函数参数传递,操作实际变量
#include "stdio.h"
#include "string.h"
void swop(int* pa,int* pb);
void main(){
int a,b;
int* pa=&a;
int* pb=&b;
char str[]="请输入两个数:";
puts(str);
scanf("%d %d",&a,&b);
printf("before the swop is %d,%d",a,b);
putchar('\n');
// 交换两个函数
swop(pa,pb);
printf("after the swop is %d,%d \n",a,b);
}
void swop(int* pa,int* pb){
int temp;
temp=*pa;
*pa=*pb;
*pb=temp;
}
实参变量值交换过程:
由数据变量改为指针变量
// 将上述程序中的Swap()函数里的局部变量temp,由数据变量改为指针变量;差别
void swop(int* pa,int* pb){
int* temp;
temp=pa;
pa=pb;
pb=temp;
} // 结果这两个数是没有改变的,因为这只是交换了形式参数的指针地址而已;如下图所示;
这些问题很好?
1、程序运行时,计算机内存区域是如何进行划分的?
2、访问内存变量时,内存变量地址和该地址下的内存变量存储单元中的数据,在存储访问上是如何操作和实现的?
3、讨论直接访问与间接访问内存变量数据方式有何不同?
4、讨论如何获得已定义变量的地址,又是如何按该地址存放变量数据的?
5、讨论指针运算有哪些实际有效的地址操作运算符,各自操作的物理特性有哪些?
6、讨论函数参数为指针类型时,传递的是指定变量的什么内容?
由指针变量传地址改为数据变量传数据
// 指针变量作为函数参数传递,操作实际变量
#include "stdio.h"
#include "string.h"
void swop(int x,int y);
void main(){
int a,b;
int* pa=&a;
int* pb=&b;
char str[]="请输入两个数:";
puts(str);
scanf("%d %d",&a,&b);
printf("before the swop is %d,%d",a,b);
putchar('\n');
// 交换两个函数
swop(a,b);
printf("after the swop is %d,%d \n",a,b);
}
void swop(int x,int y){
int temp;
temp=x;
x=y;
y=temp;
}
// 结果也是没有发生改变
形参变量值交换过程:单向传递过程
数据变量名在被定义的的时候,就永远和那个被分配好的内存地址绑定在一块了,而不是相等,代表的是该内存上的数据变量值,值可以任意改变,但变量名不变和内存地址不变;
** 数据变量名 代表:容器; 内存地址 代表:出厂编号位置;指针变量代表: 记录本记录编号
*int x=100; int p=&x; x++;(*p)++; p++// 结果:102,这时候指针p 就不指向x 了;
数组与地址指针
数组是由连续内存存储的数组元素组成;数组名就是该数组的首地址,即array[0];
数组元素引用方式:
1、下表法:array[2] 2、指针法:*(p+2);
// 编写程序,使用下表法和指针法
指针法:
数组与地址指针两种方式,来表达数组
// 数组下标法
/*#include "stdio.h"
void main(){
// 定义变量区
int a[6];
int i=0;
printf("请输入6个数:");
for(i=0;i<6;i++){
scanf("%d",&a[i]);
}
printf("\n");
// 输出数组
printf("数组输出:");
for(i=0;i<6;i++){ // 这个圆括号里面的分号 是真的很难找啊
printf("%3d",a[i]);
}
printf("\n");
}
*/
// 使用指针法
#include "stdio.h"
void main(){
// 定义变量区
int a[6];
int i;
int* p=a;
//输入数据区
printf("请输入6个数:");
for(p=a;p<a+6;p++){
scanf("%d",p); // 指针变量本身就是地址,不需要再去取它的地址
}
// 输出数组
printf("该数组是:");
p=a;
for(i=0;i<6;i++){
printf("%3d",*p);
p++;
}
printf("\n");
}
数组名作函数参数
// 将数组x中的数组元素逆序存放
// 将数组名作函数参数,将数组中的元素逆序存放
#include "stdio.h"
#define N 5
int swop(int y[]);
void main(){
// 定义变量区
int a[N]; // 定义实参数组
int i;
//定义数组1-5;并输出
for(i=0;i<N;i++){
a[i]=i+1;
}
printf("the array is:");
for(i=0;i<N;i++){
printf(" %-3d",a[i]);
}
printf("\n");
// 数组逆序存放
swop(a);
// 输出
printf("after the swop:\n");
printf("the array is:");
for(i=0;i<N;i++){
printf("%-3d",a[i]);
}
printf("\n");
}
int swop(int y[]){ // 或者在这定义一个指针变量
int i=0;
int* p=y;
int temp;
for(i=0;i<N/2;i++){
temp=*(p+i);
*(p+i)=*(p+N-1-i);
*(p+N-1-i)=temp;
}
return 0;
}
指向数组的指针变量作函数参数
指针变量可以指向地址,指针变量作为函数的参数指向数组,实现地址数据的传递
数组和指针变量传递 数组地址的方式:
// 实参和形参均使用 指针变量
// 实参和形参均使用 指针变量
#include "stdio.h"
#define N 5
int doubled(int* p); // 声明函数
void main(){
int x[N]; // 定义数组
int i =0; // 循环指针
printf("输入这个数组:");
//
for(i=0;i<N;i++){
printf("x[%d]=",i);
scanf("%d",x+i); // x 是首地址
}
printf("the array is : \n");
for(i=0;i<N;i++){
printf("x[%d]= %-3d ",i,*(x+i)); // 取数值
}
printf("after doubled is:\n");
doubled(x);
// 输出数组
for(i=0;i<N;i++){
printf("x[%d]=%-3d",i,*(x+i));
}
printf("\n");
}
int doubled(int* p){
int i;
for(i=0;i<N;i++){
*(p+i)=*(p+i)*2;
}
return 0;
}
;
多维数组与指针变量
二维数组与指针变量的 对应关系:
指针的指针:二级指针;
实际中:主要用到的就是:一级指针和二级指针
int a =100;
int p1 = &a;
int p2 = &p1;
指针变量也是一种变量,也会占用存储空间,也可以使用&获取它的地址。C语言不限制指针的级数,每增加一级指针,在定义指针变量时就得增加一个星号。p1 是一级指针,指向普通类型的数据,定义时有一个;p2 是二级指针,指向一级指针 p1,定义时有两个。
使用指针遍历二维数组 ----->来自C语言中文网
#include <stdio.h>
int main(){
int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
int(*p)[4]; // 表示p+1直接跳2*4个字节直接到下一行首地址
int i,j;
p=a;
for(i=0; i<3; i++){
for(j=0; j<4; j++) printf("%2d ",*(*(p+i)+j));
printf("\n");
}
return 0;
}
指针变量指向行 输出二维矩阵
// 使用指针变量输出二维数组
#include "stdio.h"
void main(){
// 定义变量区
int a[2][3]= {{1,2,3},{4,5,6}};
int (*p)[3]; // 这是定义指向一维数组的指针变量,这样定义基本上就是二维数组;int* p[3]:这是定义一维指针数组,数组元素是指针
int i;
int j;
p=a; // 指向行
for(i=0;i<2;i++){
for(j=0;j<3;j++){
printf("%-3d",*(*(p+i)+j)); // 这还是一级指针,*(p+i)实际上一行,只是在这地方当成行的首地址
}
printf("\n");
}
printf("a[%d][%d]=%d \n",i-1,j-1,*(*(p+1)+2));
}
理解多维数组的编址方式和访问数组元素的特点。
使用地址方式处理二维数组运算,用什么方式访问和处理数组元素数据。
基本方式使用指针访问二维数组
// 使用指针变量输出二维数组
/*#include "stdio.h"
void main(){
// 定义变量区
int a[2][3]= {{1,2,3},{4,5,6}};
int (*p)[3]; // 这是定义指向一维数组的指针变量,这样定义基本上就是二维数组;int* p[3]:这是定义一维指针数组,数组元素是指针
int i;
int j;
p=a; // 指向行
for(i=0;i<2;i++){
for(j=0;j<3;j++){
printf("%-3d",*(*(p+i)+j)); // 这还是一级指针,*(p+i)实际上一行,只是在这地方当成行的首地址
}
printf("\n");
}
printf("a[%d][%d]=%d \n",i-1,j-1,*(*(p+1)+2));
}*/
// 使用另一种指针变量来操作二维数组
#include "stdio.h"
void main(){
// 定义变量区
int a[2][3]={{1,2,3},{4,5,6}};
int i;
int* p;
p=&a[0][0];// 或者p=a[0],或者p=*a,指向二维数组首地址
for(i=0;i<6;i++){
if((p-a[0]) %3==0 && p!=a[0]){
printf("\n");
}
printf("%-5d",*p++);
}
printf("\n");
}
在二维数组中,若需要计算指定数组元素位置,就需要计算该元素在数组中,相对于数组首地址的偏移量,即相对位置;
设数组array[m][n],则计算元素array[i][j]在数组中的相对位置的公式:
i*m+j; 即为 (p+im+j);