指针(一)

内存和地址
内存:就是内部存储器,是由存储单元组成的,它是线性连续的。存储单元的最小单位是字节,一个字节是八个二进制位。
地址:为了访问内存中某个存储单元,就得给其编号,这编号就是地址。通过地址就可以访问这个地址所标识的存储单元。

内存地址按字节编号,其字长一般与主机相同。32位机使用32位地址,最多支持2的32次幂字节内存(4G)。

字长:字长是用二进制代码表达的计算机语言,是0和1组成的一串代码。计算机同一时间内处理的一组二进制数称为一个计算机的字,而这组二进制数的位数就是字长。字长指的是CPU一次能并行处理的二进制位数,如16位32位64位。

地址通常使用16进制来表示。

变量地址:系统分配给变量的内存单元的起始地址
例如:

int i;
float k;

程序编译时就给i分配的地址是0012FF44开始的存储空间,给变量k分配的地址是0012FF40开始的存储空间。

变量的访问
变量的存取方法:直接寻址和间接寻址
直接寻址:通过变量名访问变量。

int k,s;
scanf("%d",&k);
s=3*k;

上述代码中,我们定义了两个变量k,s,如果程序运行后,我们输入数字3,那么3就被“送”到了k这个变量名所对应的符号地址当中。s=3*k,就相当于从k这个变量名所对应的符号地址中把k的值3取出来,乘以3之后,再“送”到s这个变量名所对应的符号地址中。

间接寻址:通过指针访问变量。

int *pk;//定义指针变量pk。
pk=&k;//把k的地址赋值给pk就表示pk是指向了k(这里的k是上面代码段中的k)。
printf("%d",*pk);//用格式化输出函数,输出pk这个变量所指的变量的内容。

注意:

  • 指针:一个变量的地址。
  • 指针变量:用于存放变量的地址(指针的变量)。
  • 利用指针变量实现了对变量的间接访问。

指针变量的定义
一般形式:类型标识符 *标识符
其中这里的类型标识符是指指针所指的变量的标识符的类型。标识符是指针变量名。*号是指针声明符。

int *p1;
float *p2;

上述代码段中的p1就是定义了一个指向整型的指针变量。p2就是定义了一个指向单精度实型的指针变量。
作用:定义变量为指针类型,使之专门用于存放所定义类型变量的地址。
说明:

  • *用于定义指针变量,但指针变量名不包括它。如下面代码段的定义,他们定义的指针变量为p、q,而不是*p、*q
int *p;
float *q;
  • 一个指针变量只能用于指向同一类型的变量。如p只能指向整型变量,q只能用于指向实型变量。
  • 无论指针变量指向何种类型,指针变量本身都是整型的,指针变量本身也有自己的地址,占4个字节的存储空间。
  • 指针变量定义中“*”的作用:在定义指针的时候,用于申明其后的变量为指针变量,而在使用中则为一种运算符,意为取该指针指向地址所存放的内容。

指针运算

取地址运算一般形式:&变量
如:

int a,b,*p,*q;//定义整型变量a,b和指向整型变量的指针变量p、q。
scanf("%d",&a);//如在键盘上输入10,则将10放入变量a中。
p=&a;//a的地址赋给p,p里面存的就是a的地址,即p指向a。
q=p;//p赋给q,则q与p含有相同的地址值,即q也指向a。

取内容运算一般形式:*指针表达式
此时有两种情况:

  1. 若*p出现在赋值号的左边,表示给p所指变量赋值。
  2. 若*p不出现在赋值号的左边,表示p所指变量的值。

如:

int a,b,*p;
p=&a;//将a的地址赋给p,就表示p指向了变量a。
*p=10;//表示把10赋值给p所指的单元,也就是把10赋给了变量a。
printf("%d\n",*p);//输出p所指的单元的内容,即输出a当中的值。
scanf("%d",&a);//用格式化输入函数从键盘中所输入的值,送到变量名a所对应的地址当中。即给变量a输入值。
scanf("%d",p)//把键盘输入的值送入到p所指的单元中,实际上也是给变量a输入值。
b=*p+25;//就是要把p所指的单元的内容,也就是a的值10取出来加上25,再赋给变量b。

总体印象:有整型变量a和指向整型的指针变量p,那么p和&a一样都是表示地址,而*p和a一样都表示内容。

为指针变量赋初值
指针变量使用前必须有值。并且指针变量的初值必须是地址值(不能是整数)。可以有两种方式给指针变量初始化:

  • 定义指针变量时同时初始化
int a,*p=&a;
  • 使用赋值语句赋值:
int a,*p;
p=&a;

在格式化输入输出头文件中有一个符号定义,把NULL定义为0,即NULL是在stdio.h中定义的符号常数#define NULL 0 它是一个空地址。也就是说可以为指针赋空值(NULL),此时指针不指向任何变量,如:

p=NULL;//(p为空指针变量),不提倡p=0;或者p='\0'

变量的两种赋值方式
例:

int i,k,*i_pointer;
i=10;
i_pointer=&i;
k=i;//直接访问。
k=*i_pointer;//间接访问。

其存储单元中逻辑关系如下图所示:
这里写图片描述

指针与一维数组
数组中的每一个元素都可以通过下标唯一确定,即通过下标可以访问(操作)数组中的元素。
在C语言中,凡是可以通过数组下标形式完成的访问(操作)均可通过指针方式实现。
C语言规定:数组名就是数组的首地址常量,即int a[10]; 那么a[0]这个元素的地址就是数组的首地址,那么a==&a[0]
C语言系统内部处理机制,指针方式效率高,但不直观。
访问数组的两种方式:

  • 下标方式:
int a[10],*p;//定义数组及指向数组元素的指针。
p=a;//等价于p=&a[0];使p指向a数组的第一个元素a[0]。
//a[i]、*(a+i)、p[i]、*(p+i)等价。
  • 指针方式:

通过指向数组元素的指针变量访问所需元素。

int a[10],*p=&a[0];
p++;//通过指针引用数组。
//输出数组全部元素
//下标法
#include<stdio.h>
int main(){
    int a[10],i;
    for(i=0;i<10;i++)
        scanf("%d",&a[i]);
    printf("\n");
    for(i=0;i<10;i++)
        printf("%3d",a[i]);
    return 0;
}
//指针法
#include<stdio.h>
int main(){
   int a[10],i,*p=a;
   for(i=0;i<10;i++,p++)
      scanf("%d",p);
   printf("\n");
   for(p=a;p<(a+10);p++)
      printf("%3d",*p);
   return 0;
}

指针的运算
指针的运算包括:
指针的算术运算

  • 指针表达式与整数的加减运算
  • 指针自增自减运算

指针的关系运算
同类指针相减
强制类型转换运算

指针表达式与整数的加减运算
一般形式:p+n或p-n 其中p是任意一个指针表达式,n是任何一种整型表达式。
计算规则:
表达式p+n的值=p的值+p所指类型长度*n
表达式p-n的值=p的值-p所指类型长度*n
只有当p和p+n或p-n都指向连续存放的同类型数据区域(数组)时,指针加、减才有实际意义,表达式p+n和p-n的类型与p相同。如:

int a[10],*p,*q;
p=a;
q=a+6;

这里写图片描述
数组和指针本质的不同:

  • 数组名是指针常量,不能改变指针常量的值,a++;a+=2;a=p;都是非法的。
  • 指针p是变量,若p指向数组的首地址,p+1代表该类型的下一变量的地址。

指针自增自减运算
语法:后缀:p++; p–; 前缀:++p; –p;
说明:

  • 进行++p或p++运算后都使p指向下一个数据。
  • 表达式p++的值等于p的原来的值;表达式++p的值等于p的新值。
  • 取内容运算符“*”,取地址运算符“&”和自增自减运算符都是单目运算符,运算的优先级相同,结合方向都是自左至右。

指针的关系运算
当两个指针指向同一个数组中的元素时,才能进行>、<、>=、<=、!==、==的关系运算。
任何指针p与NULL进行“p==NULL”或“p!=NULL”运算均由意义,判断指针p是否指向空。
指针的关系运算只有同类指针进行比较才有意义。
假设p和q指向同一个数组,则:
语法:指针表达式 关系运算符 指针表达式

  1. ==和!=运算符,比较两个指针表达式是否指向同一个内存单元。
  2. >、<、>=、<=,比较两个指针所指内存区域的先后次序。

p>q:p指针所指元素位于q所指元素之时为1,反之为0。
p>=q:p指针所指元素位于q所指元素之(或两指针指向同一元素)时为1,反之为0。
p==q:两指针指向同一元素时为1,反之为0。
p!=q:两指针不指向同一元素时为1,反之为0。

同类指针相减
语法:p-q
说明:

  • 同类指针相减时,两个指针应该指向连续存放的同类数据区域。
  • p-q的值=(p的值-q的值)/所指类型长度,即p、q两个指针之间数据元素的个数。如:
int a[10],*p,*q;
p=a;
q=&a[5];//则p-q=5,表示p-q之间数据元素的个数是5。

强制类型转换运算
格式:(类型名 *)指针表达式
功能:将指针表达式的值转换成指定类型的指针。如:

int *p;
double d,*q=&d;
p=(int *)q;
//给定十个整数求最大值
#include<stdio.h>
int main(){
   int i,a[10]={5,7,3,6,2,1,8,9,4,0},*p,max;
   p=a;
   max=*p++;
   for(i=1;i<10;i++,p++)
      if(*p>max)max=*p;
   printf("max=%d\n",max);
   return 0;
}

字符指针与字符串
字符串是双引号括起来的一串字符,在C语言中没有字符串这种数据类型,但可以用两种方式表示一个字符串。
字符串的表示形式:
用字符数组表示,如

int main(){
    char string[]="I love China!";
    printf("%s\n",string);
    return 0;
}

用字符指针实现,如

int main(){
    char *string="I love China!";//这里只是把字符串的首地址赋给了string。
    printf("%s\n",string);
    return 0;
    //特点是:字符串的长度不受限制,字符指针指向别处,字符串将失踪。并且此字符串不能改变,只能读取。
}

字符指针变量与字符数组的区别
字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是字符串的首地址。赋值方式:char str[]="I am a boy";char str[20]; gets(str);
字符指针变量指向字符串首地址。赋值方法三种:char *pa="I am a boy!";char *pa; pa="I am a boy!",如果要修改文字内容,必须按下面的方式处理:

char str[20],*pa=str;
gets(str);
//或scanf("%s",pa);或scanf("%s",str);但这两种输入方式不能输入空格、或者、/符号。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值