C语言:指针

指向变量的指针

定义格式

数据类型说明符 *变量名

如 int *p1, *p2;

指针变量赋值

用表示地址的数据为指针赋值,如数组名,&变量名

相同类型的指针可以相互赋值

// 初始化时赋值

int a=1, *b=&a;

// 赋值语句

int a=1,*b;

b = &a;    // 没有*号

例子:判断输入值大小

#include <stdio.h>

int main(int argc, char *argv[]) { 
	int *p1, *p2, *p, a, b;
	scanf("%d,%d", &a, &b);
	p1 = &a, p2 = &b;	// 为指针赋值 
	if (a < b) {
		p = p1;
		p1 = p2;
		p2 = p;		// 交换指针的值 
	} 
	printf("a=%d, b=%d\n", a, b);
	printf("max=%d, min=%d\n", *p1, *p2);	// 输出被指针所指变量的值 
	return 0;
}

指向数组的指针

因为数组名表示的是数组首元素的地址,所以指针和数组名可以使用相同的方便访问数组

#include <stdio.h>

int main(int argc, char *argv[]) { 
	int i, a[] = {1,2,3,4,5}, *p = a;
	for (i = 0; i < 5; i++) {
		printf("%d %d %d\n", a[i], *(a + i), *(p + i));
	}
	return 0;
}
/* 输出: 
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
*/

指针运算

取地址运算 &

取内容运算 *

指针赋值运算

用变量的地址给指针赋值

用同类型的指针给指针赋值

用数组名为指针赋值

指针可以进行有限的算数运算和关系运算

加减运算:指针可以和正整数进行加减运算,加n表示指针当前指向的元素之后第n个位置的指针,减法同理

关系运算:两个指针可以进行关系运算,当两个指针指向同一个数组区域内时,关系运算符表示两个指针各自指向元素的位置关系,靠前则小于,靠后则大于

两个指针的减法运算:当两个指针指向同一个数组区域内时,两个指针的减法则表示各自指向的元素在数组中的距离的单位长度

// 判断字符串长度
#include <stdio.h>

int strlen(char *s) {
	if (*s == '\0') {
		return 0;
	} else {
		return 1 + strlen(s + 1);	// 表达式s+1表示指向数组内后一个元素的指针 
	}
}

int main(int argc, char *argv[]) { 
	char a[10] = "china";
	int k = 0;
	k = strlen(a);
	printf("%d", k);
	return 0;
}

指针和数组名的区别

一维数组名表示数组的首地址,也可以进行算数运算和关系运算,但还是存在一些区别:

指针的值为字符串首字符的地址,数组名的值由各个元素组成

指针的内存地址在运行时分配一个存储内存地址的空间,数组名在编译时分配内存,有确定的地址

#include <stdio.h>

void copy_with_array() { 
	// 通过array的方式copy字符串 
	char a[] = "I am a boy.", b[20];
	int i;
	for (i = 0; *(a + i) != '\0'; i++) {
		*(b + i) = *(a + i); 
	}
	*(b + i) = '\0';
	printf("string a is : %s\n", a);
	printf("string b is : ");
	for (i = 0; *(b + i) != '\0'; i++) {
		printf("%c", *(b + i));
	}
}

void copy_with_pointer() {
	// 通过指针的方式copy字符串 
	char a[] = "I am a boy.", b[20], *p1, *p2;
	int i;
	p1 = a; p2 = b;
	for (; *p1 != '\0'; p1++, p2++) {	// 指针累加 
		*p2 = *p1;
	}
	*p2 = '\0';
	printf("string a is : %s\n", a);
	printf("string b is : ");
	for (i = 0; b[i] != '\0'; i++) {
		printf("%c", b[i]);
	}
	printf("\n");
}

int main(int argc, char *argv[]) { 
	copy_with_array();
	copy_with_pointer();
	return 0;
}

指向二位数组元素的指针

当指针指向二位数组内某行的值上时(包含该行首地址),则算数运算表示指针在列上移动,而非在行上移动

#include <stdio.h>

int main(int argc, char *argv[]) { 
	int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
	int *p;
	for (p = a[0]; p < a[0] + 12; p++) {	// a[0]表示指向二维数组第0行的首地址,此时算数运算是指向元素的指针的运算 
		if ((p - a[0]) % 4 == 0) {
			printf("\n");
		}
		printf("%4d", *p);
	}
	return 0;
}

二维数组地址讨论

a, a[0], *(a+0), *a, &a[0][0]相等

a表示二维数组的首地址

a[0]表示第一个一维数组的数组名和首地址

*(a+0)或*a是与a[0]等效的,表示一维数组a[0]中0号元素的地址

a[i], &a[i], *(a+i)和a+i相同

不存在元素a[i],它是一种地址计算方法,表示数组a第i行第0号元素的地址

a[i] + j表示元素地址(重点理解)

a[0]可以看成是a[0] + 0,是一位数组a[0]的0号元素的地址,而a[i] + j则表示一维数组a[i]的j号元素地址,它等价于&a[i][j]

指针访问二维数组值

由a[i] = *(a+i)可得a[i] + j = *(a + j) + j,因为它们都是表示地址,所以可以通过取内容运算访问值:*(*(a + j) + j)

特殊的a(重点理解)

由于a既表示整个二位数组,又表示首个一维数组的首地址,所以在取地址&运算和取内容运算*时有些特殊:

对a取内容的结果和a本身表示的结果一样,都是第一个一维数组首地址

对a取地址和对*a取地址以及**a取地址一样,也都是第一个一维数组首地址

#include <stdio.h>

int main(int argc, char *argv[]) { 
	int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
	printf("%d\n", a);
	printf("%d\n", *a);
	printf("%d\n", **a);
	printf("%d\n", &(a));
	printf("%d\n", &(*a));
	printf("%d\n", &(**a));
	return 0;
}
/* 打印
6487536
6487536
1
6487536
6487536
6487536 
*/

行指针

定义格式

类型说明符 (*指针变量名)[长度]

例如: int (*p)[4]

行指针是一种指向固定长度的一维数组的指针

p + i表示指向一维数组a[i]

*(p + i)  + j表示指向二维数组第i行的第j列

#include <stdio.h>

int main(int argc, char *argv[]) { 
	int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
	int (*p)[4], i, j;
	p = a;	// 将行指针p指向二维数组第0行的首地址
	scanf("i=%d, j=%d", &i, &j);
	printf("a[%d,%d]=%d\n", i, j, *(*(p + i) + j));	// 通过行指针访问元素 
	return 0;
}

行指针做形参的函数

#include <stdio.h>

int main(int argc, char *argv[]) { 
//	void average(float *p, int n);
//	void search(float (*p)[4], int n); 
	int k;
	float score[3][4] = {{65, 67, 70, 60}, {80, 87, 56, 43}, {99, 78, 76, 100}};
	scanf("%d", &k);
	average(*score, 12);
	search(score, k); 
	search(*score, k); 
	return 0;
}

/* 求全部分数的平均分 */
void average(float *p, int n) {
	float *p_end;
	float sum = 0, aver;
	p_end = p + n -1;
	for (;p <= p_end; p++)
		sum = sum + *p;
	aver = sum / n;
	printf("average=%5.2f\n", aver);
} 

/* 输出指定学生的成绩 */
void search(float (*p)[4], int n) {	// 行指针做形参
	int i;
	printf("the score of No.%d are:", n);
	for (i = 0; i < 4; i++) {
		printf("%7.2f", *(*(p + n) + i));	// 在第n行上移动指针 
	} 
	printf("\n");
} 
/* 打印 
1
average=73.42
the score of No.1 are:  80.00  87.00  56.00  43.00
the score of No.1 are:  80.00  87.00  56.00  43.00
*/

指向函数的指针

函数的首地址:函数的入口地址,函数的首地址就是函数名

指向函数的指针变量:存放函数入口地址(函数指针)的变量,称为指向函数的指针变量

函数指针定义

函数指针的定义和行指针的区别是,前者的使用小括号,后者使用中括号

类型 (*函数指针变量名)(形参表);

例如: float (*pf)(int a[])

函数指针赋值

函数指针变量名 = &函数名

pf = &max;

pf = &min;

pf = &aver;

函数指针调用函数

(*函数指针变量名)(实参表)

(*pf)(a)

例子:指向函数的指针

#include <stdio.h>

int max(int *p) {
	int i, t = *p;
	for (i = 0; i < 10; i++) {
		if (*(p + i) > t) {
			t = *(p + i);
		}
	}
	return t;
}

int main(int argc, char *argv[]) { 
	int i, m, a[10];
	int (*pf)(int a[]);
	for (i = 0; i < 10; i++) {
		scanf("%d", &a[i]);
	}
	pf = &max;
	m = (*pf)(a);
	printf("max=%d\n", m);
	return 0;
}

返回指针的函数

定义

其中的*表示返回的是地址

类型名 * 函数名(参数表) {函数体};

#include <stdio.h>

float * search(float (*pointer)[4], int n) {
	float *pt;
	pt = *(pointer + n);
	return pt;
}

int main(int argc, char *argv[]) { 
	float *p, score[3][4] = {{65, 67, 70, 60}, {80, 87, 56, 43}, {99, 78, 76, 100}};
	int i, m;
	printf("enter the number of student:");
	scanf("%d", &m);
	printf("The scores of No.%d are:\n", m);
	p = search(score, m);
	for (i = 0; i < 4; i++) {
		printf("%5.2f\t", *(p + i));          
	}
	return 0;
}

指针数组

如果一个数组的元素均为指针类型数据,称之为指针数组。

指针数组中的每一个元素都相当于一个指针变量

指针数组的定义

指针数组和行指针的定义方式很相似,不同的是指针数组不需要括号将*号和指针名包裹,而行指针需要

类型名 *数组名[长度]

char *p[5];

指针数组的初始化

使用地址为指针数组初始化

// 将5个字符数组的首地址分别传给指针数组里的指针

char *p[5] = {"wangxiao", "zhangyi", "wenhua", "chenxu", "liming"};

 指针数组例子

当使用指针数组进行排序时,不需要移动实际数据的内存位置,而是通过改变对应指针的指向,就可以实现排序功能

#include <stdio.h>

int main(int argc, char *argv[]) { 
	int i, k, j;
	static char *str[4] = {"program", "fortran", "c", "basic"};
	char *temp;	// 定义指针,作为临时变量交换两个字符串
	for (i = 0; i < 4; i++) {
		for (j = i + 1; j < 4; j++)
			if (strcmp(str[i], str[j]) > 0) {	// strcmp按位置判断字符的aiisc码大小 
				temp = str[j];
				str[j] = str[i];
				str[i] = temp;	
			}
	} 
	for (i = 0; i < 4; i++) {
		printf("%s\n", str[i]);
	} 
	return 0;
}

二级指针

指向指针变量的指针变量,指针的指针存放的是指针变量地址

二级指针的定义

类型 **指针变量名

int i = 2;

int *p1, **p2;

p1 = &i;

p2 = &p1;

二级指针例子

当使用指针数组指向其他多维数组时,就相当与给数组进行了降维,而指向一维指针数组的指针,就是二维数组

#include <stdio.h>

int main(int argc, char *argv[]) { 
	char *name[] = {"book", "cell phone", "table", "program", "computer"};
	char **p;
	int i;
	for (i = 0; i < 5; i++) {
		p = name + i;
		printf("%s\n", *p);
	}
	return 0;
}

指针定义及含义

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值