高级会员
- 威望
- 250
- 贡献
- 315
- 热心值
- 0
- 金币
- 23
- 注册时间
- 2020-9-29
|
指针是什么如果在程序中定义了一个变量,在对程序进行编译时,系统就会给该变量分配内存单元 编译系统根据程序中定义的变量类型,分配一定长度的空间 例如:vc2010为整型变量分配4个字节,对单精度浮点型变量分配4个字节,对字符型变量分配1个字节 内存区的每一个字节有一个编号,这就是“地址”,它相当于旅馆中的房间号 在地址所标识的内存单元中存放数据,这相当于旅馆房间中居住的旅客一样 由于通过地址能找到所需的变量单元,我们可以说,地址指向该变量单元 将地址形象化地成为“指针” 务必弄清楚存储单元的地址和存储单元的内容这两个概念的区别
直接存取和间接存取通过变量名的访问成为直接存取 通过指针变量的访问成为间接存取
指向就是通过地址来体现的假设 i_pointer中的值是变量i的地址(2000),这样就在 i_pointer和变量i之间建立起一种联系,即通过i_pointer能知道i的地址,从而找到变量i的内存单元 称i_pointer指向i 变量i_pointer称为指针变量,它保留了变量 i 的地址 由于通过地址能找到所需的变量单元,因此可以说“地址指向该变量单元”,但这样的说法不够形象和生动 将地址形象化地称为“指针”。意思是通过他能找到以他为地址的内存单元 可以通过指针指向某个存储单元,从而可以通过指针间接地访问这个存储单元 一个变量的地址称为该变量的指针,例如:地址2000 是变量 i的指针 如果有一个变量专门用来存放另一个变量的地址(即指针),则它称为 指针变量 i_pointer 就是一个指针变量,指针变量就是地址变量,即专门用来存放其他变量的地址的变量,指针变量的值是地址(即指针) 存放地址的变量是指针变量,它用来指向另一个对象,如变量、数组、函数和指针等 指针本身就是一种类型,另外指针的类型还取决于它所指向的变量的类型(基类型)包括:普通变量指针、数组指针、函数指针、指向指针的指针
int * pointer_1 //此处 * 与类型名在一起共同定义指针变量,类型名 int 用于定义指针变量的基类型
​
*pointer //此处 * 与指针变量一起使用,此时代表指针变量所指向的变量,标识 “取内容”定义指针变量定义指针变量的一般形式位: 类型 * 指针变量名; 如:int *poniter_1
指针变量定义注意事项在定义指针变量时必须指定基类型 不同类型的数据在内存中所占得字节数和存放方式是不同的 通过指针引用一个变量时,必须知道该数据的类型,才能按存储单元的长度以及数据的存储形式正确地取出该数据 指针的移动和指针的加、减运算。例如:使指针移动一个位置或者使指针值加1,这个1代表与基类型对于的字节长度 整型指针变量只能指向其定义时由“基类型”int支出的形同类型的变量,不能忽而指向int整型变量,忽而指向float实型变量
在说明指针变量时不能只说“a是一个指针变量”,而应该完整的说:
a是指向整型数据的指针变量 int *a
b是指向单精度型数据的指针变量 float *b
c是指向字符型数据的指针变量 char *c
int * ,float * ,char * 是三种不同类型的指针变量,不能混淆
指针变量中只能存放其他对象的地址(指针),不能将一个整数直接赋给一个指针变量,否则判定位非法。
下面都是合法的指针变量定义和初始化:
float *pointer_3;
char *pointer_4;
int a,b;
int *pointer_1=&a, *pointer_2=&b;怎样引用指针变量在引用指针变量时,可能有三种情况: 给指针变量赋值。如: p = &a; // 使p 指向a 引用指针变量指向的变量,如有 p = &a; *p=1; // *p相当于a 直接引用指针变量的值。如: printf("%o",p);
掌握两个与指针相关的运算符:1、& 取地址运算符。 &a 是变量a的地址 2、* 指针运算符(间接访问运算符) 如果:p指向变量 a , 则 *p 就代表 a k = *p; (把a的值赋值给k) *p = 1; (把1赋值给a)
例子: 输入 a 和 b两个整数,按先大后小的顺序输出a和b
//例题:输入3个整数,a,b,c,要求按由大到小的顺序将他们输出,用函数实现。
#include<stdio.h>
int main(){
void exchange(int *q1, int *q2, int *q3);
int a,b.c,*p1,*p2,*p3;
scanf("%d,%d,%d",&a,&b,&c);
p1 = &a;
p2 = &b;
p3 = &c;
exchange(p1,p2,p3);
printf("%d,%d,%d\n",a,b,c);
return 0;
}
void exchange(int *q1, int *q2, int *q3 ){
void swap(int *pt1, int* pt2);
if (*q1<*q2) swap(q1,q2);
if (*q1<*q3) swap(q1,q3);
if (*q2<*q3) swap(q2,q3);
}
void swap(int *pt1, int* pt2){
int temp;
temp = *pt1;
*pt1 = *pt2;
*pt2 = temp;
}易错点
#include<stdio.h>
#include<conio.h>
int main(){
float *a;
float b = 3;
a=&b;
printf("%f,%f\n",*a++,*a);
*a = 5.0;
printf("%f\n",*a);
printf("%f\n",b);
getch();
return 0;
}数组元素的指针一个变量有地址,一个数组包含若干元素,每个数组元素都有相应的地址 指针变量可以指向数组元素(把某一数组元素的地址放到一个指针变量中) 所谓数组元素的指针就是数组元素的地址 引用数组元素可以用下标法(如a[3]),也可以用指针法,即通过指向数组元素的指针找到所需的元素。 使用指针法能使目标程序质量高(占内存少,运行速度快) C 语言中,数组名(不包括形参数组名,形参数组并不占据实际的内存单元)代表数组中首元素(即序号为0的元素)的地址。它是一个指针型常量 可以用一个指针变量指向一个数组元素 int a[6] = {1,2,3,4,5,6}; int *p; p = &a[0] //等价于 p = a ;
在引用数组元素时指针的运算在指针指向数组元素时,允许以下运算:引用一个数组元素,可以用下面两种方法:
例题:通过指针变量输出整型数组a的10个元素
解题思路:用指针变量p指向数组元素,通过改变指针变量的值,使p先后指向a[0]到a[9]各元素。
#include<stdio.h>
int main(){
int *p,i,a[10];
p=a;
for(i=0;i<10;i++) scanf("%d",p++);
p=a;//一定不能掉了,这种错误在编译时不会报错,一定要注意
for(i=0;i<10;i++,p++)
printf("%d",*p);
}注意事项: 指向数组的指针变量也可以带下标,如p在编译时,对下标的处理方法时转换为地址,对p处理成*(p+i) 如果p是指向一个整型数组元素a[0],则p代表a。但如果当前p指向a[3],则 p[2]并不代表a[2],而是a[3+2],即a[5]
利用指针引用数组元素比较方便灵活,有不少技巧, p++; *p p++使p指向下一元素a[1],然后若再执行*p,则得到下一个元素a[1]的值
*p++; 由于++ 和 *同优先级,结合方向为自右向左,它等价于 *(p++)。先引用p的值,实现 *p的运算,然后再使p自增,等同 *p; p++;
*(p++) 与 *(++p)作用是否相同?
如果p当前指向 a 数组中的第i个元素a 则: *(p--) 相当于 a ,先对p进行 * 运算(求p所指向元素的值)。再使p 自减 *(++p)相当于 a[++i],先使p自加,再进行 * 运算 *(--p)相当于 a[--i],先使p自减,再进行 * 运算
//例题:想输出a数组的100个元素,可以用下面的方法:用数组名做函数参数用数组名作函数参数时,因为实参数组名代表该数组首元素的地址,形参应该是一个相应类型的指针变量 C编译都是将形参数组名作为指针变量来处理,因此可以省略数组第一维的大小 实参数组名是指针常量,而形参数组名是按指针变量处理 在函数调用进行虚实结合后,形参数组名(指针变量)的值就是实参数组首元素的地址 在函数执行期间,形参数组名(指针变量)可以再被赋值(因为它本质上是一个变量)
变量名作函数参数和数组名做函数参数的比较实参类型 变量名 数组名
要求形参的类型 变量名 数组名或指针变量
传递的信息 变量的值 实参数组首元素的地址
通过函数调用能否改变实参的值 不能改变实参变量的值 能改变实参数组的值
//将数组a中n个整数按相反顺序存放
//阶梯思路:将a[0] 与 a[n-1] 对换
#include<stdio.h>
#include<conio.h>
int main(){
void inv(int *x,int n);
int i, a[10] = {3,7,9,11,0,6,7,5,4,2};
for (i = 0; i < 10; i++) printf("%d",a);
printf("\n");
inv(a,10);
for ( i = 0; i < 10; i++) printf("%d",a);
getch();
return 0;
}
void inv(int *x,int n){
int *p,temp,*i,*j,m=(n-1) / 2;
i = x;
j=x + n - 1;
p =x + m;
for (; i <= p; i++,j--)
{
temp = *i;
*i = *j;
*j = temp;
}
}如果有一个实参数组,要想在函数中改变此数组中元素的值,函数实参与形参的对于关系 实参 形参 实参 形参
数组名数组名指针变量指针变量
数组名指针变量指针变量数组名
//用指针方法对10个整数按由大到小顺序排列
/*
解题思路:
在主函数中定义数组a存放10个整数,定义 int * 型指针变量p指向 a[10]
定义函数 sort 使数组a中的元素按由大到小的顺序排列
在主函数中调用 sort 函数 用指针 p 做实参
用选择法进行排序
什么是选择法排序?
选择法排序:假设有N个数要按照从大到小的顺序排序,选择法就是先设第一个数是最大的(进行第一次大循环),然后将这个数与数组中剩下的数依次比较,如果剩下的数中有比这个数大的,那就两者交换,直至第一个数是最大的为止;然后再设第二个数为第二大的(进行第二次大循环),将第二个数与数组中除第1、2数外的其余数进行比较,如果有大值,则进行两两交换,直至第二个数是剩下数中最大的为止。
​
*/
​
#include<stdio.h>
#include<conio.h>
int main(){
void sort(int x[], int n);
int i, *p,a[10];
p=a;
for(i=0;i<10;i++) scanf("%d",p++);
p=a;
sort(p,10);
for(p=a,i=0;i<10;i++){
printf("%d",*p);
p++;
}
printf("\n");
getch();
return 0;
}
void sort(int x[],int n){
int i,j,k,t;
for(i=0;i<n-1;i++){
k = i;
for(j=i+1;j<n;j++){
if (x[j] > x[k]) // if(*(x+j) > *(x + k))
{
k = j;
}
}
if(k != i) {
t = x; // t = *(x+i)
x = x[k]; // *(x+i) = *(x+k)
x[k] = t; // *(x+k) = t
}
}
}通过指针引用多维数组a 和 *(a+i)等价,a+j和 *(a+i)+ j等价 *(行指针) = 列指针 从二维数组角度看,a代表二维数组首元素的地址,现在的首元素不是一个简单的整型元素,而是由4个整型元素所组成的一维数组,因此a代表的是二维数组首行(即第0行)的首地址,a+1代表第一行的首地址,a+2代表第二行的首地址。 a[0],a[1],a[2],既然是一位数组名,而c语言又规定了数组名代表数组首元素地址,因此a[0]代表一维数组a[0]中第0列元素的地址,即&a 0。也就是说 a[1]的值是&a 1,a[2]的值是&a 2
提问 * (a+i)代表什么? 答:相当于 a a[0] + 2 代表 a 0的地址 (列指针每加1 ,走一列)
提问 a + j代表什么? 提问 *(a + j)代表什么? 提问 *( *(a+i) + j)代表什么? a[1]和 *(a+1)等价 a+1 和 *(a+1)、a[1]都是地址,且其值相等,都等于&a 1,区别在于 a + 1是行指针 *(a+1)、a[1] 都是列指针
在指向行的指针前面加一个 * ,就转换为指向列的指针。例如,a 和 a + 1是指向行的指针,在它们前面加一个 * 后, * a 和 *(a+1)就成为指向列的指针,分别指向a数组第0行0列的元素和 第 1行0列的元素。 反之,在指向列的指针前面加 & 就成为指向行的指针。例如 a[0]的指向第0行0列元素的列指针,在它前面加 一个 & ,得 &a[0],由于a[0]与*(a+0)等价,因此&a[0]与 & * a等价,也就是与 a 等价,它指向二维数组的第 0 行,是一个行指针。 不要把&a简单地理解为元素a的物理地址,因为并不存在a这样一个实际的数据存储单元。它只是一种地址的计算方法,能得到第 i 行的首地址(行指针方式)。 &a和a的值相同,但他们的含义不同 &a或 a+ i指向行(行指针) a或* (a+i)指向列(列指针) 它们所指向的对象不同,即指针的基类型是不同的。
*(a+i)只是a的另一种表示形式,不要简单地认为 *(a+i) 是 a+i 所指单元中的内容(实际上 a代表一个一维数组,它不是一个实际的存储单元)。 在一维数组中a+i所指的是一个数组元素的存储单元,在该单元中有具体值,上述说法是正确的,而对二维数组,a + i 不是指向具体存储单元而是指向数组a的第 i 行 在二维数组中,a + i 、&a 、a、*(a+i)、&ai的值相等,即他们都代表同一地址,其中:a + i 、&a 是行指针
例题:显示二维数组的有关数据(地址和值)
//例题1:有一个3 x 4的二维数组,要求用指向数组元素的指针变量输出二维数组各元素的值
/*
解题思路
列指针完成
1.二维数组的元素时整型的,它相当于整型变量,可以用int * 型指针变量指向它
2.二维数组的元素在内存中是按行顺序存放的,即存放完序号为0的行中的全部元素后,接着存放序号为1的行中的元素,依次类推
3。因此可用一个指向整型元素的指针变量(列指针),依次指向二维数组中的各个数组元素
*/
#include <stdio.h>
#include <conio.h>
int main(){
int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23};
int *p;//p + 1
for (p=*a; p < a[0] + 12; p++)
{
if((p - a[0]) % 4 == 0) printf("\n");
printf("%4d", *p);
}
printf("\n");
getch();
return 0;
}
​
//行指针完成
#include <stdio.h>
#include <conio.h>
int main(){
int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23};
int (*p)[4];//p + 1
int j;
for (p=a; p < a + 3; p++){
for(j=0;j < 4;j++)
{
printf("%4d", *(*p+j));
}
printf("\n");
}
getch();
return 0;
}
|
|