指向变量的指针
定义格式
数据类型说明符 *变量名
如 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;
}
指针定义及含义