C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)一:https://developer.aliyun.com/article/1530354
字符数组与字符指针
可以用字符串常量来给字符型指针进行初始化。
int *str1 = "How are you !"; //此时字符指针指向的是一个字符串常量的首地址,即指向字符串的首地址。 int *str2[] = "How are you !"; //此时,str2是字符数组,它存放的是一个字符串。
字符指针str1与字符数组str2的区别是:
str1是一个变量,可以改变str1的值,即str1可以指向不同内存单元的地址。
指针字符数组的指针
定义一个字符指针指向字符数组后,就可以利用指针来处理该字符数组中存储的字符串。使用指针处理字符串,不仅书写方便,而且程序的运行效率更高。
用指针处理字符串的方法是:首先定义一个字符指针,然后将字符数组的首地址赋值给该指针。
例如:
char str[] = "Hello world !"; char *p = str;
看下面一段代码:
#include <stdio.h> int main() { char str[] = "Hello world !"; char *p = str; printf("%s\n", p); p += 6; printf("%s\n", p); return 0; }
其运行结果为:
其中p初始化时存储了str的首地址,故打印出来了完整的字符串。
而后将指针p往后移了6位,使得其新的首地址从‘w’开始,所以打印出来的结果变成了“world!”。
指针与函数
函数型指针的定义
在C语言中,定义了函数之后,系统为该函数分配一段连续的存储空间。其中函数的起始地址称为该函数的入口地址,将此地址赋给另外一个变量,则该变量为一个指向函数的指针。
指向函数的指针变量的一般形式为:
类型说明符(* 标识符)();
其中,类型说明符为被指针所指向的函数的返回值的数据类型;标识符为一个指针名(不是函数名),该指针只能指向函数;括号中为空,但括号必须有,表示该指针是专指函数的。
例如:
int (*p)();
函数型指针的赋值
用函数名为指针初始化,表示指针指向该函数。
例如:
int (*p)(); //定义函数型指针 int fun(); //声明函数fun p = fun; //让指针p指向函数fun
关于函数型指针的赋值说明:
(1)当函数型指针指向了某一函数后,此函数的调用可以用函数名,也可以用指针(用*p代替原函数名);
(2)用函数型指针定义之后,不是固定指向某一个函数,而是先后指向不同的函数(给它赋值其他入口地址即可改变其指向的函数);
(3)为函数型指针赋值时,不必用参数;
(4)对指向函数的指针变量,先p + n,p ++,p -- 等运算是没有意义的。
指针型函数的定义与使用
调用函数,通常得到一个返回值带回主调函数。如果返回值为一个指针时,则该函数就是指针型函数。
定义形式:
类型说明符 *标识符(形参列表);
例如:
int *a(int x,int y);
其中a是函数名,调用它以后能得到一个指向整型数据的指针。x、y是函数a的形参,为整型。因此,指针型函数也就是返回指针值的函数。
利用指针型函数,求一个二维数组中的最大值,并返回它的地址
#include <stdio.h> #define ROW 3 //宏定义二维数组的行和列 #define COL 4 int* max(int a[ROW][COL]) { int *p, i, j; p = a[0]; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { //判断大小 if (*p < *(*(a + i) + j)) p = *(a + i) + j; } } return p; } int main() { int a[ROW][COL], i, j, * p; printf("请输入二维数组值:"); for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { scanf("%d", &a[i][j]); } } //将二维数组传参进函数a p = max(a); for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { printf("%d\t", a[i][j]); } printf("\n"); } printf("最大值为:%d\n", *p); return 0; }
其运行结果为:
指针数组
由若干个指针变量组成的数组,称为指针数组。指针数组也是数组的一种,所有有关数组的概念都适用它。但指针数组与普通数组又有区别,指针数组的数组元素是指针类型的,只能用来存放地址值。
指针数组的定义
定义形式:
类型说明符 *数组名[数组长度];
例如:
int *p[4];
这条语句定义了一个指针数组p,该数组中有4个元素,每个元素都是一个指针,指向int型数据。指针数组比较适合用来指向若干个字符串,使字符串处理更加方便灵活。
值得注意的是:
指针数组语句:int *p[ 4 ];符号[]的优先级比符号*高,因此变量名p先与[]结合,表示这是一个长度为4的数组;再与*和int结合,表示该数组的元素的数据类型是int * 型,每个数组元素都可以指向一个整型变量。
指针数组的初始化
指针数组是由若干个指针变量组成的数组,因此必须用地址值为指针数组初始化。
例如:
int arr[3][3] = {1,2,3,4,5,6,7,8,9}; int *pa[3] = {arr[0],arr[1],arr[2]};
由于arr是一个二维数组,所以arr[ 0 ],arr[ 1 ],arr[ 2 ]为该二维数组的每一行的首地址。
故而,可以通过指针数组来引用二维数组中的元素:
pa[i] + j = arr[i] + j = &arr[i][j]; *(pa[i] + j) = *(arr[i] + j) = arr[i][j];
用字符指针数组表示一组字符串,即每个数组元素分别指向一个字符串,然后进行字符串的比较:
#include <stdio.h> #include <string.h> int main() { char *s[4] = { "hello","Circle","Square","Rectangle" }; char *temp; int i, j, k; for (i = 0; i < 4; i++) { printf("%d:%s\n", i + 1, s[i]); //按原始顺序输出4个字符串 } for (i = 0; i < 3; i++) { //使得前一个字符串与后面几个字符串对比 k = i; for (j = i + 1; j < 4; j++) { if (strcmp(s[k], s[j]) > 0) k = j; if (k != i) { temp = s[i]; s[i] = s[k]; s[k] = temp; //交换指针指向的字符串 } } } printf("\n"); for (i = 0; i < 4; i++) { printf("%d:%s\n", i + 1, s[i]); //输出排序后的4个字符串 } return 0; }
其运行结果为:
多级指针
如果一个指针变量存放的是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,即多级指针(指向指针的指针)
多级指针定义的一般形式如下:
类型说明符 * * 指针名;
例如:
int x = 4; int *p ; int **p ; p = &x; //指针变量p指向整型变量x q = &p; //二级指针q指向指针变量p
看下面代码:
#include <stdio.h> int main() { int x = 10; int *p, **q; p = &x; q = &p; printf(" x = %d\n", x); printf(" *p = %d\n", *p); printf(" **q = %d\n", **q); return 0; }
其运行结果为:
所以说,以上三种方式都是等价的。
要注意的:指向指针的指针是间接地指向目标变量,因此,将直接指向目标变量的指针称为一级指针,将指向指针的指针称为二级指针,将指向二级指针的指针称为三级指针,以此类推。
通过指向指针的指针输出数组元素:
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { srand((unsigned int)time(NULL)); int arr[5][3],a,b,**p; int *num[5] = { arr[0],arr[1],arr[2],arr[3],arr[4] }; //指针数组 p = num; //指向指针数组的指针 for (a = 0; a < 5; a++) //随机初始化二维数组 { for (b = 0; b < 3; b++) { arr[a][b] = rand() % 20 + 1; } } for (a = 0; a < 5; a++) { for (b = 0; b < 3; b++) { printf("%2d\t", *(*p + b)); //通过二级指针输出数组元素 } printf("\n"); p++; } return 0; }
其运行结果为: