赞
踩
目录
C程序设计中使用指针可以
-使程序简洁、经凑,高效
-有效地表示复杂的数据结构
-动态分配内存
-得到多于一个的函数返回值
地址和变量
在计算机内存中,每个字节单元,都有一个编号,称为地址。
1Byte =8bit。
看到的地址是起始地址,编译或函数调用时为其分配内存单元,变量是对程序中数据存储空间的抽象。
int a = 8;
0 | 数据 |
... | 数据 |
2000 | 8 |
2001 | 数据 |
2002 | 数据 |
2003 | 数据 |
在C语言中,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量。
在不影响理解的情况中,有的对地址、指针和指针变量不区分,通称指针。
一般形式:
<存储类型> <数据类型> *<指针变量名>;
例如,auto char *pName (放的内容是char类型)
指针的存储类型是指针变量本身的存储类型。
指针说明时指定的数据类型不是指针变量本身类型,而是指针目标的数据类型。简称为指针的数据类型
指针在说明的同时,也可以被赋予初值
一般形式:
<存储类型> <数据类型> *<指针变量名> = <地址量>;
例如:
int a, *pa=&a;
在上面语句中,把变量a的地址作为初值赋予了刚说明的int类型指针pa。
- int a =3; //int a; a =3;
- int *pa = &a; //int *pa; pa = &a;
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
- int a = 10;
- int *p;
-
- p = &a;
-
- printf("&p:%p %d\n", &p,sizeof(int *));
- printf("%p %p\n", p, &a);
- return 0;
- }
-
-
- &p:0xbfa9364c 4
- 0xbfa93648 0xbfa93648 //指针变量p的地址,就是变量a的地址;
-
指针指向的内存区域中的数据称为指针的目标
如果它指向的区域是程序中的一个变量的内存空间,则这个变量称为指针的目标变量。简称为指针的目标。
引入指针要注意程序中的px、*px和&px三种表示方法的不同意义。设px为一个指针,则:
px-指针变量,它的内容是地址量
*px-指针所指向的对象,它的内容是数据
&px-指针变量占用的存储区域的地址,是个常量
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
- int a = 10;
- int *p;
-
- p = &a;
- printf("%d %d\n", a, *p);
- return 0;
- }
-
-
- 10 10
是通过赋值运算符向指针变量送一个地址值
向一个指针变量赋值时,送的值必须是地址常量或指针变量,不能是普通的整数(除了赋零以外)
- //1
- doublx x =15, *px;
- px = &x; //类型相同,都是double
- //2
- float a, *px,*py;
- px = &a;
- py = px;
- //3
- int a[20],*pa;
- pa = a; //等价于pa
什么是指针?内存以字节为单位编号,内存单元的地址称为指针,专门用来存放地址的变量,称为指针变量。
指针占几个字节?32位系统都是4个字节。
操作系统和内存有多少个地址线?32根地址线需要4G的内存,这里可以根据计算公式来得到结果,比如32根地址线的计算结果是2^32=4*1024mb=4G,所以它应该用4G内存。一般而言内存上地址线会有64个,最多支持128bit,所以无论内存多大,地址线的总数是有限制的
不同数据类型的两个指针实行加减整数运算是无意义的
px+n表示的实际位置的地址量是:(px)+sizeof(px的类型)*n
px-n表示的实际位置的地址量是: (px)-sizeof(px的类型)*n
运算符 | 计算形式 | 意义 |
+ | px+n | 指针向地址大的方向移动n个数据 |
- | px-n | 指针向地址小的方向移动n个数据 |
++ | px++或 ++px | 指针向地址大的方向移动1个数据 |
-- | px-- 或 --px | 指针向地址小的方向移动1个数据 |
- | px-py | 两个指针之间相隔数据元素的个数 |
q先赋值,后p++ 所以还是之前的值 ,如果是++p就不一样了
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
- int a[5] = {4, 8, 1, 2, 7};
- int *p,*q;
-
- p = a; //&a[0]
- printf("%p %d\n", p, *q);
- q = p++;
- printf("%p %d\n", p, *p);
- printf("%p %d\n", q, *q);
-
- return 0;
- }
-
- 0xbfa44cec -1079745597
- 0xbfa44cf0 8
- 0xbfa44cec 4 //q先赋值,后p++ 所以还是之前的值 ,如果是++p就不一样了
px-py运算的结果是两指针指向的地址位置之间相隔数据的个数。因此,两指针相减不是两指针有的地址值相减的结果。
-两指针相减的结果值不是地址量,而是一个整数值,表示两指针之间相隔数据的个数。(一般结合数组,用的频率才高)
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
- int a[5] = {4, 8, 1, 2, 7};
- int *p,*q;
-
- p = a;
- q = &a[3];
- printf("%p %p\n", p, q);
- printf("%d %d\n", *p, *q);
- printf("%d\n", q-p);
-
- return 0;
- }
-
- 0xbfdd15bc 0xbfdd15c8
- 4 2
- 3
-两指针之间的关系运算表示它们指向的地址位置之间的关系。指向地址大的指针大于指向地址小的指针。
-指针与一般整数变量之间的关系运算没有意义。但可以和0进行等于或不等于的关系运算,判断指针是否为空。
> < >= <= != ==
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
-
- int *p= NULL;
- printf("%p\n",p);
- return 0;
- }
-
- (nil)
程序举例1
第一步 --p //指向a[0]
第二步 *--p //取地址里数据
第三部 (*--p)++// 先赋值,后数据++
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
-
- int a[]={5,8,7,6,2,7,3};
- int y,*p = &a[1];
-
- y = (* --p)++;
-
- printf("%d %d",y,a[0]);
- }
-
- 5 6
程序举例2
指针可以代替数组下标
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
- int i, *p, a[7];
- p = a;
- for(i = 0; i<7; i++)
- scanf("%d",p++);
- printf("\n");
-
- p = a;
- for(i = 0; i<7; i++){
- printf("%d",*p);
- p++;
- }
- }
在C语言中,数组的指针是指数组在内存中的起始地址,数组元素的地址是指数组元素在内存中的起始地址
一维数组的数组名为一维数组的指针(起始地址)
如double x[8];x为x数组的起始地址
设指针变量px的地址值等于数组指针x(既指针变量px指向数组的首元素),则:
x[i]、*(px+i)、*(x+i)和px[i]具有完全相同的功能:访问数组第i+1个数组元素。
x[i] 和 *px
x++会报错,因为是地址常量,但是x+1,x+2可以
但是指针px++可以。
虽然都是一样,但是一个是数组名是常量,一个是指针是变量
下标法:x[i]
指针法: *(px+i)
注意
指针变量和数组在访问数组中元素时,一定条件下其使用方法具有相同的形式,因为指针变量和数组名都是地址量
但指针变量和数组的指针(或叫数组名)在本质上不同,指针变量是地址变量,而数组的指针是地址常量。
程序举例
编写一个函数,将整型数组中n个数按反序存放
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
- int buf[10]={0};
- int *p,*q,temp,n,i;
- n = 10;
- printf("please input:\n");
- for(i = 0; i < n; i++){
- scanf("%d",&buf[i]); //循环接受数字
- }
- p = buf;
- q = &buf[n-1];
-
- //冒泡算法
- while(p < q)
- {
- temp = *p;
- *p = *q;
- *q = temp;
- p++;
- q--;
- }
- }
- 2,1 Top
a[i] <<==>>*(a+i)
多维数组就是具有两个或两个以上下标的数组
在c语言中,二维数组的元素连续存储,按行优先存。
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
-
- int a[3][2] = {{1,6},{9,12},{61,12}};
- int *p, i, n;
-
- n = sizeof(a) / sizeof(int);
-
- p = a;
- printf("%p %p\n", p, p+1);
- printf("%p %p\n", a, a+1);
-
- for(i = 0; i < n; i++)
- printf("%d ",*(p+i));
- puts("");
-
- return 0;
- }
-
- //结果
- 0xbfbd2c08 0xbfbd2c0c
- 0xbfbd2c08 0xbfbd2c10
- 1 6 9 12 61 12
用一级指针遍历二维数组,p = a 类型不匹配。p是1级, a是两级,改成&a[0][0] 就没警告了,也可以写p=a[0],a[0]也是数组名。a[0]++会报错,常量不能放等号左边
二维数组名代表数组的起始地址,数组名+1,是移动一行元素。因此,二维数组名常被称为行地址
a[0] | a[0][0] |
a[0][1] | |
a[0][2] | |
a[1] | a[1][0] |
a[1][1] | |
a[1][2] | |
a[2] | a[2][0] |
a[2][1] | |
a[2][2] |
行指针(数组指针)
存储行地址的指针变量,叫做行指针变量。形式如下:
-<存储类型> <数据类型> (*<指针变量名>)[表达式];
例如: int a[2][3];
int (*p)[3];//行指针
方括号中的常量表示是表示指针加1,移动几个数据。
当用行指针操作二维数组时,表达式一般写成1行的元素个数,既列数。
程序举例:遍历二维数组,二维数组指针和行地址概念
- #include <stdio.h>
-
- int main(int argc,char *argv[]){
-
- int a[3][2] = {{1,6},{9,12},{61,12}};
- int i, j;
- int (*p)[2];
-
- p = a;
-
- printf("%p %p\n", a[0], a[0]+1);//
- printf("%p %p\n", a, a+1); //a和p是行地址指针变量
- printf("%p %p\n", p, p+1); //a和p是行地址指针变量
- 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));
- puts("");
-
- return 0;
- }
-
- 0xbfe98698 0xbfe9869c //+4
- 0xbfe98698 0xbfe986a0 //+8
- 0xbfe98698 0xbfe986a0 //+8
- 12 12 12 12
- 1 1 1 1
- 6 6 6 6
- 9 9 9 9
- 12 12 12 12
- 61 61 61 61
- 12 12 12 12
-
a[0]+1 =*a +1
如果移动一行一列*(*(a+1)+1)或*(*(p+1)+1) 等于a[1][1] 或p[1][1]
主要介绍了指针与二维数组,包括一级指针如何访问二维数组以及行指针如何访问二维数组
二维数组特点:1地址常量,地址名+1是移动一行。编程,实现二维数组遍历。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。