一级指针和指针指针就是一个变量的地址吗区别是什么?

9.1 指针与指针变量的概念内存地址——内存中存储单元的编号变量地址 ---- 系统分配给变量的内存单元的起始地址指针与指针变量(1) 指针即是地址指针实际上就是内存地址.(2)指针变量就是专门用于存储其他变量地址的变量一个指针变量的值就是某个内存单元的地址(或指针)“指针”是指地址,是常量.“指针变量”是指取值为地址的变量.定义指针的目的是为了通过指针去访问内存单元9.2 指针变量的定义和引用变量值的存取方法指针变量的定义定义格式: [存储类型] 数据类型符 *变量名定义说明:
数据类型符可以是任何一种有效的数据类型标识符,是指针变量所之乡的内存房源的数据类型
(1)单个指针变量的定义int *p1;P1是一个指针变量,它的值是某个整形变量的地址.staic int *p2P2是指静态整型变量的指针变量.(2)一条语句中同时定义普通变量和指针变量float *p3, a; 或者 int a, *p3(3)一条语句中定义多个指针变量char *p4 ,*p5注意:
定义指针变量时, *号和变量名是一个逻辑整体指针变量也是变量int *p 定义的指针变量是P
指针变量的赋值指针变量的赋值只能赋予地址.(1)指针变量初始化的方法int a; int *p = &a;p、 &a、 &(*p)这些都是A的地址.(2)赋值语句的方法int a; int *p; p = &a;a *p *(&a)这些都是A的值.注意:
赋值语句中,被赋值的指针变量P的前面不能加 *不能用auto变量的地址去初始化static型指针‘*’ 和 ‘&’ 是相反的类型: * 取数值 , & 取地址零指针与空类型指针(1)零指针(空指针)指针变量的值为0的指针. 其表示形式为 int *p=0; 表示P指向地址为0 的单元,系统保证该单元不作它用,表示指针变量值没有意义. 也可以写成: #define NULL(void *)0. int *p=NULL定义零指针的用途主要表现在两个方面:
避免指针变量的非法引用在程序中常作为状态比较例如:int *p; ..... while(p!=NULL) {....}(2)void * 类型指针表示形式为 void *p; 表示不指定p 是指向哪一种数据类型的指针变量. 使用时要进行强制转换.引用指针变量当一个指针指向一个变量时,程序就可以利用这个指针间接引用这个变量. 间接引用的格式为: *指针变量. 在指针变量说明中, " * "是类型说明符, 表示其后的变量是指针类型, 而表达式中出现的 “ * ”则是一个运算符用以表示指针变量所指的变量.int a ;
int *p = &a; //P指向A
*p = 10;
//相当于A =10;
注意:
“ * ” 是间接引用运算符,是单目运算符,优先级与++ , – 相同,具有右结合性.上面的 程序中,与A++等价的表达式是( * p)++, 而不是 * p++.因为 * p++相当于 * (p++), 其中的++ 是作用于p的,而不是作用于 * p.程序在利用指针间接引用内存单元时,将按照指针变量定义时指向的数据类型来解释引用的内存单元.
/*
不同类型的指针操作同一内存变量
*/
void main()
{
unsigned short a;
unsigned short *pi = &a;
char *pc = (char *)&a;
*pi = 0xF0F0;
*pc = 0;
printf("a=%X",a);
}
//输出: A= F000
/*程序说明: pi是指向short型数据的指针,因此pi可操作整个a所对应的内存单元, *pi就是a
但pc是指向char 型数据的指针,只能操作a的低字节单元, *pc 不是short型数据,而是char型数据,所以说, *pc不是a,而是a 的低字节
*/
执行前:执行后:/*输入两个数,并使其从大到小输出*/
void main()
{
int *p1, *p2, *p, a, b;
scanf("%d,%d",&a,&b);
p1 = &a; p2 = &b; //P1指向变量a, p2指向变量b
if(a<b)
{
//将 p1,p2所指向的变量地址交换
p=p1;
p1=p2;
p2=p;
}
printf("a =%d , b=%d\n",a,b);
printf("max = %d, min = %d\n",*p1,*p2);
}
//输入 10
20
//运行结果: a = 10, b = 20
//
max =20 ,min=10;
注意:
指针变量必须先定义,后赋值,最后才能使用! 没有赋值的指针变量是没有任何意义的,也是不能使用的指针变量只能指向定义时所贵姓类型的变量
9.3 指针的地址运算指针变量的加、减运算指针是地址, 地址是一个无符号的整数,乘/除没有任何意义.但是指针可以参与加法和减法运算, 如果指针P是这样定义的: ptype *p ; 并且P当前的值是ADDR那么: p +- n的值 = ADDR +- N * sizeof(ptype)P将以sizeof(ptype)为单位进行加减.int *pi;
char *pc;
long *pl;
pi=(int *)1000;
pc(char *)1000;
pl=(long *)1000;
pi++ //pi的值将是1002(假设int占 2byte)
pi-=2; // pi = 998
pc++; //pc = 1001
pc-=2; //pc = 999
pl++; //pl = 1004
pl-=2; //pi = 996
注意: 两个指针相加没有任何意义, 但两个指针相减则有一定的意义,可以表示两指针之间所相差的内存单元数或元素的个数.指针变量的关系运算两个指针变量进行关系运算可表示他们所指向的内存单元之间的关系.p1==p2 表示P1和P2指向同一内存单元
p1>p2 表示P1处于高地址的位置
p1<p2 表示P1处于低地址位置
9.4 指针与数组9.4.1 数组的指针和指向数组的指针变量数组的指针数组的指针其实就是数组在内存中的起始地址. 而数组在内存中的起始地址就是数组变量名, 也就是数组第一个元素在内存中的地址.指向数组的指针变量如果将数组的起始地址赋给某个指针变量,那么该指针变量就是指向数组的指针变量.int a[10], *p=a;(或*p=&a[0];)或者:int a[10], *p; p=a;(或p=&a[0];)a[k]的地址与a的运算关系:注意:
p+i和 a+i 都是数组元素a[i]的地址
(p+i) 和 * (a+i)就是数组元素a[i]指向数组的指针变量,也可将其看作是数组名,因而可按下标法来使用. 例如: p[i] 等价于*(p+i),也等价于a[i] 注意: >
**P+1 指向数组的下一个元素,而不是简单的使指针变量的值+1.** >其变化为; p+1*size (size为一个元素占用的字节数)
对数组元素赋值的方法:// 1.
char str[10];
int k;
for(k=0;k<10;k++)
str[k] ='A' + k;
//也可以写成 *(str+k) = 'A' +k;
//2.
char str[10];
int k;
char *p;
p = str;
for(k=0;k<10;k++)
p[k] = 'A' +k;
//也可以写成*(p+k)='A'+k
//3.
char str[10];
int k;
char *p;
p=str;
for(k=0;k<10;k++)
*p++ = 'A' +k;
//相当于 *p='A'+k; p++;
注意:
2和3都是通过指针变量来对数组赋值,但程序执行完后,指针变量p的内容是不一样的,方法2 执行完后,p仍然指向数组str的首地址,方法3 执行完后p 指向了数组元素str[9]的下一个内存单元. (这就是数组越界的现象.)
9.4.2指向多维数组的指针----数组指针例:利用一般指针变量对二维数组的引用#include<stdio.h>
void main(){
short int a[2][3] ={{1,2,3},{4,5,6}};
short int i, j, *p;
p = &a[0][0]; //也可以写成p=a[0]; p指向二维数组a的第一个单元
for(i=0;i<2;i++) //变量i 控制行数
{
for(j=0;j<3;j++) //变量j控制列数
printf("a[%d][%d] = %d ",i ,j, *(p+i*3+j)); //显示每个数组的元素的值
printf("\n); //数组的每一行元素输出后换行
}
}
//运行结果: a[0][0] =1
a[0][1] =2 a[0][2] =3 a[1][0] =4 a[1][1] =5 a[1][2] =6
注意:假设有一个M行N列的二维数组a:
a[i] 为第 i+1行的首地址, 是一个地址常量. a[0]是整个二维数组元素所占内存单元的首地址当二维数组的首地址赋给指针变量p 以后, 则访问某个元素 a[ i ][ j ]可以用这几种方式来代替:*(p+i*n+j)、p[i*n]+j、*(a[0]+i*n+j)二维数组名a不可赋值给一般指针变量p,只能赋值给指向二维数组的指针变量
指向二维数组的指针变量其定义格式为:数据类型符 (*指针变量名) [常量表达式];注意: 常量表达式必须是二维数组的第二维的大小例如:int a [2] [3]; 则定义一个指向二维数组a 的指针变量p 应为 int(p)[3]***//利用指向二维数组的指针变量对二位数组的引用
#include<stdio.h>
void main(){
short int a[2][3] ={{1,2,3},{4,5,6}};
short int (*p)[3];
short int i, j;
p=a ;
//p指向二维数组的第一行行地址
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("a[%d][%d] = %d", i, j,p[i][j]); //显示每个数组元素的值
printf("\n);
}
}
p++;
//p指向二维数组A的第二行行地址
for(j=0;j<3;j++)
printf("%d",p[0][j]);
//显示数组中第二上的元素值
}
//运行结果: a[0][0] = 1
, a[0][1] = 2 , a[0][2] = 3 , a[1][0] = 4
// a[1][1] = 5 a[1][2] = 6
// 4 5 6
指向二维数组的指针与二维数组元素的关系注意:
对指向二维数组的变量进行赋值一般为:二维数组名+整型常数N .如: p=a+1&二维数组名[整型常量] 如:p=&a[1]
不可用数组单元地址对其赋值如: p=a[0] ; 或 p = &a [0] [0]都是做错误的
a + i = &a[i] 这是第i 行的元素,是整行的元素*(a+ i)=a [i ] = &a [i][0] 这是第 i 行中的第一个元素, 如果想表示第2行第3个元素: a[2]+3 = (a+2)+3((a+i)+j) :a 是a的首地址, a+i 代表第i行的一行指针 ,(a+i)+j 代表第i行第j列元素的地址, ((a+i)+j)相当于a[i ][ j],是i,j 的值. 9.4.3元素为指针的数组----指针数组一般格式: 数据类型符 *变量名[常量表达式];指针数组与数组指针定义的结合顺序指针数组与二维数组指针的区别//利用指针数组对键盘输入的5个整数进行从小到大排序
void main()
{
int i, j, t;
int a, b, c, d, e;
int *p[5] ={&a,&b,&c,&d,&e};
//将ABCDE的内存地址分别赋值给 p[0],p[1],...
scanf("%d,%d,%d,%d,%d",p[0],p[1],p[2],p[3],p[4]); //对ABCDE赋值
for(i=0;i<4;i++) //用冒泡算法排序
for(j=i+1;j<5;j++)
if(*p[i]>*p[j]) //交换p[i],p[j]所指向的变量值
{
t=*p[i];
*p[i] = *p[j];
*p[j] = t;
}
for(i=0;i<5;i++)
printf("%d ",*p[i]);
}
//输入 3,8,7,6,4
//输出 3,4,6,7,8
9.5 指针与字符串字符串的本质其实是以’\0’结尾的字符型数组.字符串在内存中的起始地址(第一个字符的地址)称为字符串的指针字符串的表示可以用字符数组表示字符串, 也可以用字符指针变量来表示字符串.如: char srt[] = "I love china";(1)便定义边赋值定义字符指针变量时对其赋初始值,其一般格式为:char *字符指针变量名 = 字符串常量;例如: char *pstr = "i love china"(2)先定义后赋值char *字符指针变量名;
字符指针变量名 = 字符串常量;
//例如: char *pstr;
pstr = "I love china"
引用字符串(1)逐个字符引用使用字符指针变量表示和逐个医用字符串中的字符#include<stidio.h>
void main()
{
char *pstr = "i love china";
for(;*pstr !='\0';pstr++)
printf("%c",*pstr);
}
注意: 字符指针变量pstr中,仅存储字符串常量的首地址,而字符串常量的内容(字符串本身),是存储在由系统自动开辟的内存块中,并在串尾添加一个结束标志’\0’(2) 整体引用#include<stdio.h>
void mian()
{
char *pstr = "i love china";
printf("%s",pstr);
}
字符指针变量与字符数组比较(1)存储内容不同字符指针变量中存储的是字符串的首地址,而字符数组中存储的是字符串本身(2)赋值方式不同对字符指针变量,可采用下面的赋值语句赋值:char *pointer; pointer = "this is a example.;而字符数组,虽然可以定义时初始化,但是不能赋值语句整体赋值(3)地址常量与地址变量不同指针变量的值可以改变的,字符指针变量也不例外; 而数组名代表数组的起始地址,是一个地址常量,而常量是不能被改变的
字符指针变量使用注意事项当字符指针指向字符串时,除了可以被赋值外,与包含字符串的字符数组没有什么区别
char str[10], *pstr;
pstr = "12345";
strcpy(str,pstr); //将pstr所指向的字符串赋值到数组str中
pstr = str;
printf("%d",strlen(pstr));
//输出pstr所指向的字符串的长度5
野指针有可能出现系统死机!字符指针变量的应用//利用字符指针实现字符串的倒序排列.
#include<stdio.h>
#include<string.h>
void main()
{
char str[200],ch;
char *p, *q;
gets(str);
//读取一个字符串
p=str;
//p指向字符串的首地址
q=p+strlen(p)-1 //q指向字符串的末地址
while(p<q)
{
//交换P和Q个字指向的字符
ch = *p;
//将P指向的字符保存在CH中,
*p++ = *q; // 将Q指向的字符赋值给P指向的字符单元, P再增1
*q-- = ch; //将CH的值 赋给Q指向的字符单元,Q再减1
}
printf("%s\n",str);
}
9.6 指针与动态内存分配 静态内存分配定义变量或数组以后,系统会给内存单元,这种就是静态内存分配; 这些内存就是在程序运行前就分配好了,不可改变
动态内存分配动态分配的内存需要有一个指针变量记录内存的起始地址void *malloc (unsigned int size)注意:
size 这个参数的含义是分配的内存的大小
例子://根据学生人数来建立数组的问题
int n, *pscore;
scanf("%d",&n);
pscore = (int *)malooc(n * sizeof(int));
if(pscore == NULL) //分配内存失败
{
printf("insufficient memory available!");
exit(0);
}
注意: >malloc前面必须要加上一个指针类型转换符, 因为malloc的返回值是空类型的指针,一般应与右边的指针变量类型一致 >malloc所待的一个参数是指需分配的内存单元字节数,一般写成`分配数量 * sizeof(内存单元类型符)` >malloc 可能返回NULL,表示分配内存失败, 如果有空指针会造成系统崩溃
动态内存释放void free(void *block);block为分配的动态内存的首地址.9.7 多级指针二级指针的定义与引用[存储类型] 数据类型符 **变量名;如:int a 3;
int *p1;
int **p2;
p1=&a;
p2=&p1;
**p2 = 5;
//A的值从3变成了5
二级指针的应用//利用二级指针来处理字符串
#include<stdio.h>
#define NULL 0
void main()
{
char **p;
char *name[] = {"hello","good","world","bye"," "};
p = name +1;
//现在指向name[1], good
printf("%x:%s ", *p,*p);
p+=2; //name[3], bye
while(**p!=NULL)
printf("%s\n",*p++);
}
注意:
二级指针与指针数组的关系: int **p 与 int *q[10]指针数组名是二级指针常量p = q; p+i是q[i]的地址指针数组作形参时, int *q[ ]与 int **q 完全等价;系统只给p 分配能保存一个指针值的内存区; 而给q分配10块内存区,每块可保存一个指针值.
9.8 指针作为函数的参数想通过一个函数来改变调用函数中的变量的值.方法一: 因为 B和A分别对应不同的内存单元, 调用的函数的时,只是吧A对应的内存单元的值改变为5,并没有改变B对应的内存单元的值.方法二: 是把变量B的地址(&b)传送给指针型参数P,这样指针P就指向了对应的内存单元赋值,所以B的值就发生了改变.从上面的程序我们知道,定义函数时,形参前面有一个 * 号,就表明形参时指针型参数,如果有两个 * 号,就表明形参是指针的指针(二级指针).//求某矩阵中行元素之和的最大值
int GetSumRow(int *p, int num);
int FetMaxRow(int **p, int row, int col);
void main()
{
int row, col;
int i, j, **p, maxrow;
printf("intput row = ");
scanf("%d",&row);
printf("input col=");
scanf("%d",&col);
//根据键入的矩阵的行数和列数来动态建立一个二维数组p
p=(int **)malloc(row * sizeof(int *));
for(i=0;i<row;i++)
for(j=0;j<col;j++)
scanf("%d",p[i]+j);
//调用函数来计算矩阵中所有行元素之和的最大值.
maxrow=GetMaxRow(p,row,col);
printf("------------------------\n");
printf("maxrow = %d\n",maxrow);
//释放动态分配的内存空间
for(i=0;i<row;i++)
free(p[i]);
free(p);
}
//计算矩阵中所有行元素之和的最大值
int GetMaxRow(int **p,int row, int col)
{
int i, max, t;
max = GetSumRow(p[0],col);
for(i=1;i<row;i++)
{
t = GetSumRow(p[i],col);
if(t>max)
max=t;
}
return(max);
}
//计算矩阵中某行元素之和
int GetSumRow(int *p;int num)
{
int i, sum =0;
for(i=0;i<num;i++)
sum+=p[i];
return(sum);
}
/*
运行结果
input row =3
input col = 4
intput the number:
3 -4 6 8
4 6 -2 7
0 9 8 6
maxrow =23
*/
对于指针参数来说,如果程序想通过函数为指针变量分配内存,则形参必须是一个指针的指针(二级指针)void getmen(int **p, int num)
{
*p=(int *)malloc(num *sizeof(int));
return;
}
void main()
{
int *pint, k;
getmen(&pint,10); //执行后,pint的值会变化
for(k=0;k<10;k++)
pint[k]=k;
//正确
....
}
9.9 指针作为函数的返回值 ---- 指针函数定义:函数类型 *函数名([形参1,形参2,....])如果一个函数返回一个指针, 不能返回auto型局部变量的指针,但可以返回static型的变量的地址.例子:int *getdata(int num)
{
static int a[100];
int k;
if(num>100) return (NULL);
for(k=0;k<num;k++)
scnaf("%d",&a[k]);
return(a);
}
//因为auto生存期短,所以需要用static型,其生存期等同于全局变量的生存期.
总结 : 编写一指针函数常量采用的方法有两种:
在函数中使用动态内存分配(malloc), 以其首地址返回就是在函数中使用静态(static)变量或全局变量, 以其存储单元的首地址返回.9.10 指向函数的指针----函数指针 函数指针的概念一个函数在编译时,被分配了一个入口地址,用函数名来表示,这个地址就称为该函数的指针. 可以用一个指针变量指向一个函数,然后通过该指针变量调用此函数.
函数指针变量(1)定义格式函数类型 (*指针变量)([形参类型1,形参类型2......])注意:
指针变量是专门存放函数入口地址,可指向返回值类型相同的不同函数;(2)赋值函数名代表该函数的入口地址,因此,可用函数名给指向函数的指针变量赋值.函数指针 =[&]函数名;其中,函数名后不能带括号和参数,函数名前的 & 符号是可选的例如:int max(int a,int b)
{
return (a>b?a:b)
}
int (*p)(int ,int);
//定义函数指针P
p=max; //将函数所对应的内存单元首地址(函数名MAX)赋给函数指针P
(3)调用格式函数指针变量([实参1,实参2,.....]); 或 (*函数指针变量)([实参1,实参2.....])上面定义的函数指针P经赋值后,可以这样调用函数MAX:p(2,3); 或 (*p)(2,3); 等价于max(2,3)函数指针的应用//用函数指针变量作参数,求最大值、最小值和两数之和
int max(int,int);
int min(int,int);
int add(int,int);
void process(int, int, int (*fun)(int,int));
void main()
{
int a,b;
scanf("%d%d",&a,&b);
process(a,b,max);
process(a,b,min);
process(a,b,add);
}
void process(int x, int y, int(*fun)(int,int))
{
int result;
result =(*fun)(x,y);
printf("%d\n",result);
}
int max(int x,int y)
{
printf("max = ");
return (x>y?x:y);
}
int min(int x,int y)
{
printf("min = ");
return(x<y?x:y);
}
int add(int x,int y)
{
printf("sum =");
return(x+y);
}
9.11 带参数的main函数在OS状态下,为执行某个程序而键入的一行字符称为命令行命令行的形式:命令名 参数1 参数2 参数3......参数N带参数的main函数为:void main(int argc, char *argv[])
{
......
}
例如: 显示命令行参数void main()
{
while(argc-->0)
printf("%s\n",*argv++);
}
//输入命令行: c:\> test hello world
/*
运行结果为:
test
hello
world
*/
9.12 小结常见的于指针相关的变量定义两个指针所指向的字符串是否相等,应该调用strcmp函数.函数返回值的类型由在定义该函数时所指定的函数}

我要回帖

更多关于 指针就是一个变量的地址吗 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信