C语言程序设计-10 指针

	指针是C语言中广泛使用的一种数据类型。运用指针编程是C语言最主要的风格之一。

利用指针变量可以表示各种数据结构;能很方便地使用数组和字符串;并能象汇编语言一样
处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。学习指针是
学习C语言中最重要的一环,能否正确理解和使用指针是我们是否掌握C语言的一个标志。
同时,指针也是C语言中最为困难的一部分,在学习中除了要正确理解基本概念,还必须要
多编程,上机调试。只要作到这些,指针也是不难掌握的。

10.1 地址指针的基本概念

在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个
内存单元,不同的数据类型所占用的内存单元数不等,如整型量占 2 个单元,字符量占 1
个单元等,在前面已有详细的介绍。为了正确地访问这些内存单元,必须为每个内存单元编
上号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。
既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指
针。 内存单元的指针和内存单元的内容是两个不同的概念。 可以用一个通俗的例子来说明
它们之间的关系。我们到银行去存取款时, 银行工作人员将根据我们的帐号去找我们的存
款单, 找到之后在存单上写入存款、取款的金额。在这里,帐号就是存单的指针, 存款数
是存单的内容。对于一个内存单元来说,单元的地址即为指针,其中存放的数据才是该单元
的内容。在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指
针变量的值就是某个内存单元的地址或称为某内存单元的指针。
在这里插入图片描述
图中,设有字符变量 C,其内容为“K”(ASCII 码为十进制数 75),C 占用了 011A 号单元
(地址用十六进数表示)。设有指针变量 P,内容为 011A,这种情况我们称为 P 指向变量 C,
或说 P 是指向变量 C 的指针。
严格地说,一个指针是一个地址,是一个常量。而一个指针变量却可以被赋予不同的指
针值,是变量。但常把指针变量简称为指针。为了避免混淆,我们中约定:“指针”是指地
址,是常量,“指针变量”是指取值为地址的变量。定义指针的目的是为了通过指针去访问
内存单元。
既然指针变量的值是一个地址,那么这个地址不仅可以是变量的地址,也可以是其它数
据结构的地址。在一个指针变量中存放一个数组或一个函数的首地址有何意义呢? 因为数
组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数
组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指针变量来表示,只要该指
针变量中赋予数组或函数的首地址即可。这样做,将会使程序的概念十分清楚,程序本身也
精练,高效。在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。 用
“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也是一
个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清
楚,表示更为明确。 这也是引入“指针”概念的一个重要原因。

10.2 变量的指针和指向变量的指针变量

10.2.1定义一个指针变量

10.2.2指针变量的引用

【例 10.1】

#include <stdio.h>main()
{int a, b;int *pointer_1, *pointer_2;a = 100;b = 10;pointer_1 = &a;pointer_2 = &b;printf("%d,%d\n", a, b);printf("%d,%d\n", *pointer_1, *pointer_2);
}

【例 10.2】输入 a 和 b 两个整数,按先大后小的顺序输出 a 和 b。

#include <stdio.h>main()
{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("\na=%d,b=%d\n", a, b);printf("max=%d,min=%d\n", *p1, *p2);
}

10.2.3指针变量作为函数参数

【例 10.3】题目同例 10.2,即输入的两个整数按大小顺序输出。今用函数处理,而且用指
针类型的数据作函数参数。

#include <stdio.h>swap(int *p1, int *p2)
{int temp;temp = *p1;*p1 = *p2;*p2 = temp;
}
main()
{int a, b;int *pointer_1, *pointer_2;scanf("%d,%d", &a, &b);pointer_1 = &a;pointer_2 = &b;if (a < b)swap(pointer_1, pointer_2);printf("\n%d,%d\n", a, b);
}

【例 10.4】请注意,不能企图通过改变指针形参的值而使指针实参的值改变。

#include <stdio.h>swap(int *p1, int *p2)
{int *p;p = p1;p1 = p2;p2 = p;
}
main()
{int a, b;int *pointer_1, *pointer_2;scanf("%d,%d", &a, &b);pointer_1 = &a;pointer_2 = &b;if (a < b)swap(pointer_1, pointer_2);printf("\n%d,%d\n", *pointer_1, *pointer_2);
}

【例 10.5】输入 a、b、c3 个整数,按大小顺序输出。

#include <stdio.h>swap(int *pt1, int *pt2)
{int temp;temp = *pt1;*pt1 = *pt2;*pt2 = temp;
}
exchange(int *q1, int *q2, int *q3)
{if (*q1 < *q2)swap(q1, q2);if (*q1 < *q3)swap(q1, q3);if (*q2 < *q3)swap(q2, q3);
}
main()
{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("\n%d,%d,%d \n", a, b, c);
}

10.2.4指针变量几个问题的进一步说明

【例 10.6】

#include <stdio.h>main()
{int a = 5, *p = &a;printf("%d", *p);
}

【例 10.7】

#include <stdio.h>main()
{int a = 10, b = 20, s, t, *pa, *pb; /*说明 pa,pb 为整型指针变量*/pa = &a;                            /*给指针变量 pa 赋值,pa 指向变量 a*/pb = &b;                            /*给指针变量 pb 赋值,pb 指向变量 b*/s = *pa + *pb;                      /*求 a+b 之和,(*pa 就是 a,*pb 就是 b)*/t = *pa * *pb;                      /*本行是求 a*b 之积*/printf("a=%d\nb=%d\na+b=%d\na*b=%d\n", a, b, a + b, a * b);printf("s=%d\nt=%d\n", s, t);
}

【例 10.8】

#include <stdio.h>main()
{int a, b, c, *pmax, *pmin;        /*pmax,pmin 为整型指针变量*/printf("input three numbers:\n"); /*输入提示*/scanf("%d%d%d", &a, &b, &c);      /*输入三个数字*/if (a > b){              /*如果第一个数字大于第二个数字...*/pmax = &a; /*指针变量赋值*/pmin = &b;} /*指针变量赋值*/else{pmax = &b; /*指针变量赋值*/pmin = &a;} /*指针变量赋值*/if (c > *pmax)pmax = &c; /*判断并赋值*/if (c < *pmin)pmin = &c;                            /*判断并赋值*/printf("max=%d\nmin=%d\n", *pmax, *pmin); /*输出结果*/
}

10.3 数组指针和指向数组的指针变量

10.3.1指向数组元素的指针

10.3.2通过指针引用数组元素

【例 10.9】输出数组中的全部元素。(下标法)

#include <stdio.h>main()
{int a[10], i;for (i = 0; i < 10; i++)a[i] = i;for (i = 0; i < 5; i++)printf("a[%d]=%d\n", i, a[i]);
}

【例 10.10】输出数组中的全部元素。(通过数组名计算元素的地址,找出元素的值)

#include <stdio.h>main()
{int a[10], i;for (i = 0; i < 10; i++)*(a + i) = i;for (i = 0; i < 10; i++)printf("a[%d]=%d\n", i, *(a + i));
}

【例 10.11】输出数组中的全部元素。(用指针变量指向元素)

#include <stdio.h>main()
{int a[10], I, *p;p = a;for (i = 0; i < 10; i++)*(p + i) = i;for (i = 0; i < 10; i++)printf("a[%d]=%d\n", i, *(p + i));
}

【例 10.12】

#include <stdio.h>main()
{int a[10], i, *p = a;for (i = 0; i < 10;){*p = i;printf("a[%d]=%d\n", i++, *p++);}
}

几个注意的问题:

  1. 指针变量可以实现本身的值的改变。如 p++是合法的;而 a++是错误的。因为 a 是数组
    名,它是数组的首地址,是常量。
  2. 要注意指针变量的当前值。请看下面的程序。
    【例 10.13】找出错误。
#include <stdio.h>main()
{int *p, i, a[10];p = a;for (i = 0; i < 10; i++)*p++ = i;for (i = 0; i < 10; i++)printf("a[%d]=%d\n", i, *p++);
}

【例 10.14】改正。

#include <stdio.h>main()
{int *p, i, a[10];p = a;for (i = 0; i < 10; i++)*p++ = i;p = a;for (i = 0; i < 10; i++)printf("a[%d]=%d\n", i, *p++);
}
  1. 从上例可以看出,虽然定义数组时指定它包含 10 个元素,但指针变量可以指到数组以
    后的内存单元,系统并不认为非法。
  2. p++,由于++和同优先级,结合方向自右而左,等价于*(p++)。
  3. (p++)与(++p)作用不同。若 p 的初值为 a,则*(p++)等价 a[0],*(++p)等价 a[1]。
  4. (*p)++表示 p 所指向的元素值加 1。
  5. 如果 p 当前指向 a 数组中的第 i 个元素,则
    *(p–)相当于 a[i–];
    *(++p)相当于 a[++i];
    *(–p)相当于 a[–i]。

10.3.3数组名作函数参数

同样,指针变量的值也是地址,数组指针变量的值即为数组的首地址,当然也可作为函
数的参数使用。
【例 10.15】

#include <stdio.h>float aver(float *pa);
main()
{float sco[5], av, *sp;int i;sp = sco;printf("\ninput 5 scores:\n");for (i = 0; i < 5; i++)scanf("%f", &sco[i]);av = aver(sp);printf("average score is %5.2f", av);
}
float aver(float *pa)
{int i;float av, s = 0;for (i = 0; i < 5; i++)s = s + *pa++;av = s / 5;return av;
}

【例 10.16】将数组 a 中的 n 个整数按相反顺序存放。
算法为:将 a[0]与 a[n-1]对换,再 a[1]与 a[n-2] 对换……,直到将 a[(n-1/2)]与
a[n-int((n-1)/2)]对换。今用循环处理此问题,设两个“位置指示变量”i 和 j,i 的初值为
0,j 的初值为 n-1。将 a[i]与 a[j]交换,然后使 i 的值加 1,j 的值减 1,再将 a[i]与 a[j]
交换,直到 i=(n-1)/2 为止,如图所示。
在这里插入图片描述

#include <stdio.h>void inv(int x[], int n) /*形参x是数组名*/
{int temp, i, j, m = (n - 1) / 2;for (i = 0; i <= m; i++){j = n - 1 - i;temp = x[i];x[i] = x[j];x[j] = temp;}return;
}
main()
{int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};printf("The original array:\n");for (i = 0; i < 10; i++)printf("%d,", a[i]);printf("\n");inv(a, 10);printf("The array has benn inverted:\n");for (i = 0; i < 10; i++)printf("%d,", a[i]);printf("\n");
}

对此程序可以作一些改动。将函数 inv 中的形参 x 改成指针变量。
【例 10.17】对例 10.16 可以作一些改动。将函数 inv 中的形参 x 改成指针变量。
程序如下:

#include <stdio.h>void inv(int *x, int n) /*形参x为指针变量*/
{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;}return;
}
main()
{int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};printf("The original array:\n");for (i = 0; i < 10; i++)printf("%d,", a[i]);printf("\n");inv(a, 10);printf("The array has benn inverted:\n");for (i = 0; i < 10; i++)printf("%d,", a[i]);printf("\n");
}

执行结果

The original array:
3,7,9,11,0,6,7,5,4,2,
The array has benn inverted:
2,4,5,7,6,0,11,9,7,3,

【例 10.18】从 0 个数中找出其中最大值和最小值。
调用一个函数只能得到一个返回值,今用全局变量在函数之间“传递”数据。程序如下:

#include <stdio.h>int max, min; /*全局变量*/
void max_min_value(int array[], int n)
{int *p, *array_end;array_end = array + n;max = min = *array;for (p = array + 1; p < array_end; p++)if (*p > max)max = *p;else if (*p < min)min = *p;return;
}
main()
{int i, number[10];printf("enter 10 integer umbers:\n");for (i = 0; i < 10; i++)scanf("%d", &number[i]);max_min_value(number, 10);printf("\nmax=%d,min=%d\n", max, min);
}

说明:

  1. 在函数 max_min_value 中求出的最大值和最小值放在 max 和 min 中。由于它们是全局,
    因此在主函数中可以直接使用。
  2. 函数 max_min_value 中的语句:
    max=min=*array;
    array 是数组名,它接收从实参传来的数组 numuber 的首地址。
    array 相当于(&array[0])。上述语句与 max=min=array[0];等价。
  3. 在执行 for 循环时,p 的初值为 array+1,也就是使 p 指向 array[1]。以后每次执行 p++,
    使 p 指向下一个元素。每次将*p 和 max 与 min 比较。将大者放入 max,小者放 min。
  4. 函数 max_min_value 的形参 array 可以改为指针变量类型。实参也可以不用数组名,而
    用指针变量传递地址。
    【例 10.19】程序可改为:
#include <stdio.h>int max, min; /*全局变量*/
void max_min_value(int *array, int n)
{int *p, *array_end;array_end = array + n;max = min = *array;for (p = array + 1; p < array_end; p++)if (*p > max)max = *p;else if (*p < min)min = *p;return;
}
main()
{int i, number[10], *p;p = number; /*使p指向number数组*/printf("enter 10 integer umbers:\n");for (i = 0; i < 10; i++, p++)scanf("%d", p);p = number;max_min_value(p, 10);printf("\nmax=%d,min=%d\n", max, min);
}

【例 10.20】用实参指针变量改写将 n 个整数按相反顺序存放。

#include <stdio.h>void inv(int *x, int n)
{int *p, m, 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;}return;
}
main()
{int i, arr[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2}, *p;p = arr;printf("The original array:\n");for (i = 0; i < 10; i++, p++)printf("%d,", *p);printf("\n");p = arr;inv(p, 10);printf("The array has benn inverted:\n");for (p = arr; p < arr + 10; p++)printf("%d,", *p);printf("\n");
}

注意:main 函数中的指针变量 p 是有确定值的。即如果用指针变作实参,必须现使指针变
量有确定值,指向一个已定义的数组。
【例 10.21】用选择法对 10 个整数排序。

#include <stdio.h>main()
{int *p, i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};printf("The original array:\n");for (i = 0; i < 10; i++)printf("%d,", a[i]);printf("\n");p = a;sort(p, 10);for (p = a, i = 0; i < 10; i++){printf("%d ", *p);p++;}printf("\n");
}
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])k = j;if (k != i){t = x[i];x[i] = x[k];x[k] = t;}}
}

说明:函数 sort 用数组名作为形参,也可改为用指针变量,这时函数的首部可以改为:
sort(int *x,int n) 其他可一律不改。

10.3.4指向多维数组的指针和指针变量

【例 10.22】

#include <stdio.h>main()
{int a[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};printf("%d,", a);printf("%d,", *a);printf("%d,", a[0]);printf("%d,", &a[0]);printf("%d\n", &a[0][0]);printf("%d,", a + 1);printf("%d,", *(a + 1));printf("%d,", a[1]);printf("%d,", &a[1]);printf("%d\n", &a[1][0]);printf("%d,", a + 2);printf("%d,", *(a + 2));printf("%d,", a[2]);printf("%d,", &a[2]);printf("%d\n", &a[2][0]);printf("%d,", a[1] + 1);printf("%d\n", *(a + 1) + 1);printf("%d,%d\n", *(a[1] + 1), *(*(a + 1) + 1));
}

【例 10.23】

#include <stdio.h>main()
{int a[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};int(*p)[4];int i, j;p = a;for (i = 0; i < 3; i++){for (j = 0; j < 4; j++)printf("%2d ", *(*(p + i) + j));printf("\n");}
}

10.4 字符串的指针指向字符串的针指变量

10.4.1字符串的表示形式

C 语言中,可以用两种方法访问一个字符串。
1) 用字符数组存放一个字符串,然后输出该字符串。
【例 10.24】

#include <stdio.h>main()
{char string[] ="I love China !";printf("%s\n", string);
}

【例 10.25】

#include <stdio.h>main()
{char *string ="I love China !";printf("%s\n", string);
}

【例 10.26】输出字符串中 n 个字符后的所有字符。

#include <stdio.h>main()
{char *ps = "this is a book";int n = 10;ps = ps + n;printf("%s\n", ps);
}

【例 10.27】在输入的字符串中查找有无‘k’字符。

#include <stdio.h>main()
{char st[20], *ps;int i;printf("input a string:\n");ps = st;scanf("%s", ps);for (i = 0; ps[i] != '\0'; i++)if (ps[i] == 'k'){printf("there is a 'k' in the string\n");break;}if (ps[i] == '\0')printf("There is no 'k' in the string\n");
}

【例 10.28】本例是将指针变量指向一个格式字符串,用在 printf 函数中,用于输出二维
数组的各种地址表示的值。但在 printf 语句中用指针变量 PF 代替了格式串。 这也是程序
中常用的方法。

#include <stdio.h>main()
{static int a[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};char *PF;PF = "%d,%d,%d,%d,%d\n";printf(PF, a, *a, a[0], &a[0], &a[0][0]);printf(PF, a + 1, *(a + 1), a[1], &a[1], &a[1][0]);printf(PF, a + 2, *(a + 2), a[2], &a[2], &a[2][0]);printf("%d,%d\n", a[1] + 1, *(a + 1) + 1);printf("%d,%d\n", *(a[1] + 1), *(*(a + 1) + 1));
}

**【例 10.29】本例是把字符串指针作为函数参数的使用。要求把一个字符串的内容复制到另
一个字符串中,并且不能使用 strcpy 函数。函数 cprstr 的形参为两个字符指针变量。pss
指向源字符串,pds 指向目标字符串。注意表达式:(pds=pss)!=`\0’的用法。

#include <stdio.h>cpystr(char *pss, char *pds)
{while ((*pds = *pss) != '\0'){pds++;pss++;}
}
main()
{char *pa = "CHINA", b[10], *pb;pb = b;cpystr(pa, pb);printf("string a=%s\nstring b=%s\n", pa, pb);
}

【例 10.30】简化后的程序如下所示。

#include <stdio.h>cpystr(char *pss, char *pds)
{while (*pds++ = *pss++);
}
main()
{char *pa = "CHINA", b[10], *pb;pb = b;cpystr(pa, pb);printf("string a=%s\nstring b=%s\n", pa, pb);
}

10.4.2使用字符串指针变量与字符数组的区别

10.5 函数指针变量

【例 10.31】本例用来说明用指针形式实现对函数调用的方法。

#include <stdio.h>int max(int a, int b)
{if (a > b)return a;elsereturn b;
}int main() // 注意main函数的返回类型应当是int,同时建议显式返回0表示程序正常结束
{int (*pmax)(int, int); // 指针的声明应明确参数类型,虽然在某些编译器上可省略,但明确指定更佳int x, y, z;pmax = max; // 此处无需更改printf("input two numbers:\n");scanf("%d%d", &x, &y);z = (*pmax)(x, y); // 此处无需更改printf("maximum=%d", z);return 0; // 添加return语句
}

10.6 指针型函数

【例 10.32】本程序是通过指针函数,输入一个 1~7 之间的整数,输出对应的星期名。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>char *day_name(int n); // 添加函数原型声明int main() // 建议明确指定main函数的返回类型为int
{int i;printf("input Day No:\n");scanf("%d", &i);if (i < 0)exit(1);printf("Day No:%2d-->%s\n", i, day_name(i));return 0; // 主函数正常结束应返回0
}char *day_name(int n)
{static char *name[] = {"Illegal day","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};return ((n < 1 || n > 7) ? name[0] : name[n]);
}

10.7 指针数组和指向指针的指针

10.7.1指针数组的概念

【例 10.33】通常可用一个指针数组来指向一个二维数组。指针数组中的每个元素被赋予
二维数组每一行的首地址,因此也可理解为指向一个一维数组。

#include <stdio.h>main()
{int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};int *pa[3] = {a[0], a[1], a[2]};int *p = a[0];int i;for (i = 0; i < 3; i++)printf("%d,%d,%d\n", a[i][2 - i], *a[i], *(*(a + i) + i));for (i = 0; i < 3; i++)printf("%d,%d,%d\n", *pa[i], p[i], *(p + i));
}

【例 10.34】指针数组作指针型函数的参数。在本例主函数中,定义了一个指针数组 name,
并对 name 作了初始化赋值。其每个元素都指向一个字符串。然后又以 name 作为实参调用
指针型函数 day_name,在调用时把数组名 name 赋予形参变量 name,输入的整数 i 作为第二
个实参赋予形参 n。在 day_ name 函数中定义了两个指针变量 pp1 和 pp2,pp1 被赋予 name[0]
的值(即name),pp2 被赋予 name[n]的值即(name+ n)。由条件表达式决定返回 pp1 或 pp2
指针给主函数中的指针变量 ps。最后输出 i 和 ps 的值。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>main()
{static char *name[] = {"Illegal day","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};char *ps;int i;char *day_name(char *name[], int n);printf("input Day No:\n");scanf("%d", &i);if (i < 0)exit(1);ps = day_name(name, i);printf("Day No:%2d-->%s\n", i, ps);
}
char *day_name(char *name[], int n)
{char *pp1, *pp2;pp1 = *name;pp2 = *(name + n);return ((n < 1 || n > 7) ? pp1 : pp2);
}

【例 10.35】输入 5 个国名并按字母顺序排列后输出。现编程如下:

#include "string.h"
#include <stdio.h>main()
{void sort(char *name[], int n);void print(char *name[], int n);static char *name[] = {"CHINA", "AMERICA", "AUSTRALIA","FRANCE", "GERMAN"};int n = 5;sort(name, n);print(name, n);
}
void sort(char *name[], int n)
{char *pt;int i, j, k;for (i = 0; i < n - 1; i++){k = i;for (j = i + 1; j < n; j++)if (strcmp(name[k], name[j]) > 0)k = j;if (k != i){pt = name[i];name[i] = name[k];name[k] = pt;}}
}
void print(char *name[], int n)
{int i;for (i = 0; i < n; i++)printf("%s\n", name[i]);
}

10.7.2指向指针的指针

【例 10.36】使用指向指针的指针。

#include <stdio.h> // 只保留必需的头文件int main() // 明确main函数的返回类型为int
{// 定义一个字符串数组char *names[] = {"Follow me","BASIC","Great Wall","FORTRAN","Computer design" // 修正拼写错误:desighn -> design};// 使用指针遍历并打印数组中的每个字符串for (int index = 0; index < 5; ++index) // 使用更直观的变量名,并使用++运算符置于变量后,这是一种常见的编码风格{char **pointer = names + index; // 明确指出此指针用于指向数组中的字符串printf("%s\n", *pointer);}return 0; // 程序成功执行完毕,返回0
}

【例 10.37】一个指针数组的元素指向数据的简单例子。

#include <stdio.h>main()
{static int a[5] = {1, 3, 5, 7, 9};int *num[5] = {&a[0], &a[1], &a[2], &a[3], &a[4]};int **p, i;p = num;for (i = 0; i < 5; i++){printf("%d\t", **p);p++;}
}

10.7.3main 函数的参数

【例 10.38】

#include <stdio.h>main(int argc, char *argv)
{while (argc-- > 1)printf("%s\n", *++argv);
}

10.8 有关指针的数据类型和指针运算的小结

10.8.1有关指针的数据类型的小结

在这里插入图片描述

10.8.2指针运算的小结

现把全部指针运算列出如下:

  1. 指针变量加(减)一个整数:
    例如:p++、p–、p+i、p-i、p+=i、p-=i
    一个指针变量加(减)一个整数并不是简单地将原值加(减)一个整数,而是将该指针
    变量的原值(是一个地址)和它指向的变量所占用的内存单元字节数加(减)。
  2. 指针变量赋值:将一个变量的地址赋给一个指针变量。
    p=&a; (将变量 a 的地址赋给 p)
    p=array; (将数组 array 的首地址赋给 p)
    p=&array[i]; (将数组 array 第 i 个元素的地址赋给 p)
    p=max; (max 为已定义的函数,将 max 的入口地址赋给 p)
    p1=p2; (p1 和 p2 都是指针变量,将 p2 的值赋给 p1)
    注意:不能如下:
    p=1000;
  3. 指针变量可以有空值,即该指针变量不指向任何变量:
    p=NULL;
  4. 两个指针变量可以相减:如果两个指针变量指向同一个数组的元素,则两个指针变量值
    之差是两个指针之间的元素个数。
  5. 两个指针变量比较:如果两个指针变量指向同一个数组的元素,则两个指针变量可以进
    行比较。指向前面的元素的指针变量“小于” 指向后面的元素的指针变量。

10.8.3void 指针类型

ANSI 新标准增加了一种“void”指针类型,即可以定义一个指针变量,但不指定它是指向
哪一种类型数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/855256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 指针——字符数组与字符指针:字符串的输入和输出

目录 逐个字符输入输出字符串 整体输入输出字符串 用scanf输入/输出字符串 用gets输入/输出字符串 用scanf输入/输出字符串 用gets输入/输出字符串 逐个字符输入输出字符串 #define STR_LEN 80 char str[STR_LEN 1 ]; 整体输入输出字符串 用scanf输入/输出字符串 用gets…

【CVPR2021】LoFTR:基于Transformers的无探测器的局部特征匹配方法

LoFTR&#xff1a;基于Transformers的局部检测器 0. 摘要 我们提出了一种新的局部图像特征匹配方法。我们建议先在粗略级别建立像素级密集匹配&#xff0c;然后再在精细级别细化良好匹配&#xff0c;而不是按顺序进行图像特征检测、描述和匹配。与使用成本体积搜索对应关系的密…

oracle12c到19c adg搭建(二)oracle12c数据库软件安装

运行安装程序 不勾选 只安装软件 选择单实例安装 选择语言 企业版 确认目录 产品目录 用户组 开始安装 执行root脚本 [rooto12u19p software]# /u01/app/oraInventory/orainstRoot.sh Changing permissions of /u01/app/oraInventory. Adding read,write permissions for gro…

字节豆包大模型API吞吐、函数调用能力、长上下文能力测试总结

离开模型能力谈API价格都是耍流氓&#xff0c;豆包大模型作为API最便宜的模型之一&#xff0c;最近向个人开发者开放了&#xff0c;花了300元和一些时间对模型的API吞吐、函数调用能力、长上下文能力等进行了深度测试&#xff0c;看看它的能力究竟适合做 AI 应用开发吗&#xf…

【Anaconda】【Windows编程技术】【Python】Anaconda的常用命令及实操

一、Anaconda终端 在安装Anaconda后&#xff0c;电脑上会新增一个Anaconda终端&#xff0c;叫Anaconda Prompt&#xff0c;如下图&#xff1a; 我们选择“打开文件位置”&#xff0c;将快捷方式复制一份到桌面上&#xff0c;这样日后就可以从桌面上方便地访问Anaconda终端了&…

用python实现多文件多文本替换功能

用python实现多文件多文本替换功能 今天修改单位项目代码时由于改变了一个数据结构名称&#xff0c;结果有几十个文件都要修改&#xff0c;一个个改实在太麻烦&#xff0c;又没有搜到比较靠谱的工具软件&#xff0c;于是干脆用python手撸了一个小工具&#xff0c;发现python在…

微服务中的相关概念

Eureka Eureka 是由 Netflix 开发的一个服务发现和注册中心&#xff0c;广泛应用于微服务架构中。Eureka 主要用于管理和协调分布式服务的注册和发现&#xff0c;确保各个服务之间能够方便地找到并通信。它是 Netflix OSS&#xff08;Netflix Open Source Software&#xff09…

C#心跳机制客户端

窗体&#xff08;richTextBox右显示聊天&#xff09; 步骤 点击链接按钮 tcpclient客户端步骤 1创建客户端对象 2连接服务器connect 3创建网络基础流发消息 .write发消息 4 创建网络基础流接消息 .read接消息 5 断开连接…

python库离线安装方法(pyqt5离线安装方法)

在某些情况下&#xff0c;我们的计算机是无法联网的。 网上大部分方法&#xff1a; 这些方法都有个问题&#xff0c;就是库是需要依赖其它库的&#xff0c;你不知道它需要依赖什么库&#xff0c;就是提供了依赖库的列表也麻烦&#xff0c;依赖库也是有对应版本要求的&#xf…

自制调色小工具给图片加滤镜,修改图片红、绿、蓝通道及亮度,修改图片颜色

上篇&#xff1a; 上篇我们给地图添加了锐化、模糊等滤镜&#xff0c;这篇来写一个小工具给图片调色。 调色比锐化等滤镜要简单许多&#xff0c;直接拿到像素值修改即可。不需要用到卷积核。。。(*^▽^*) 核心原理就是图像结构&#xff0c;使用context.getImageData获取图像像…

cad怎么转成pdf文件?方法很简单!

cad怎么转成pdf文件&#xff1f;在数字化时代&#xff0c;CAD图纸的转换与共享已成为日常工作中的常态。无论是建筑设计师、工程师还是学生&#xff0c;都可能遇到需要将CAD文件转换为PDF格式的需求。本文将为您推荐三款高效的CAD转PDF软件&#xff0c;让您轻松实现文件格式的转…

C++ 48 之 继承的基本语法

#include <iostream> #include <string> using namespace std;// 定义一个基类&#xff0c;把公共的部分写在这里&#xff0c;以后让别的类继承即可 class BasePage{ public:void header(){cout << "公共的头部"<< endl;}void footer(){cout…

STM32单片机-BKP和RTC

STM32单片机-BKP和RTC 一、Unix时间戳1.1 时间戳转换 二、BKP(备份寄存器)三、RTC(实时时钟)3.1 RTC工作原理 四、代码部分4.1 BKP备份寄存器4.2 RTC实时时钟 一、Unix时间戳 Unix时间戳定义为从伦敦时间的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒时间戳…

vue3使用echarts简单教程~~概念篇

没写过 写着玩玩 不足的地方还望小伙伴补充~~ 概念篇 文档奉上&#xff1a;数据集 - 概念篇 - 使用手册 - Apache EChartshttps://echarts.apache.org/handbook/zh/concepts/dataset <template><div id"main" style"width: 600px; height: 400px&…

集合进阶:增强for循环和lambda表达式

一.增强for遍历 1.增强for的底层是迭代器,为了简化迭代器的代码书写的。 2.他是JDK5之后出现的,其内部原理就是一个lterrator迭代器。 3.所有的单列集合和数组才能用增强for进行遍历 二.格式 for(元素的数据类型 变量名;数组或者集合){} 三.代码 Collection<String>…

72-UDP协议工作原理及实战

#ifndef UDPCOMM_H #define UDPCOMM_H#include <QMainWindow> #include <QUdpSocket> // 用于发送和接收UDP数据报 #include <QtNetwork>QT_BEGIN_NAMESPACE namespace Ui { class udpComm; } QT_END_NAMESPACEclass udpComm : public QMainWindow {Q_OBJECT…

定个小目标之刷LeetCode热题(23)

今天写这道题&#xff0c;背过八股文的都应该知道LRU算法缓存的基本原理&#xff0c;在 Java 语言中&#xff0c;同样有类似的数据结构 LinkedHashMap&#xff0c;本题我们采用自己创建哈希表双链表的形式简单实现一下 对于get操作&#xff1a;通过cache.get(key)获取&#xff…

格雷母线定位与控制系统:确保机车平稳运行的关键

微深节能的格雷母线高精度位移检测系统是一种高精度的位置检测设备&#xff0c;它通过发射和接收信号来确定移动物体的实时位置。在机车定位系统中&#xff0c;格雷母线被安装在固定的轨道上&#xff0c;而机车上的检测装置则负责读取这些信号&#xff0c;从而准确计算出机车的…

一文弄懂 Python os.walk(),轻松搞定文件处理和目录遍历

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ Python os 模块的 walk() 方法以自顶向下或自底向上的方式遍历指定的目录树&#xff0c;从而显示目录树中的文件名。对于目录树中的每个目录&#xff0c;os.walk() 方法都会产生一个包含目录路径、当前…

Java17 --- redis7缓存双写一致性

一、缓存双写一致性 如果redis中有数据&#xff1a;需要和数据库中的值相同。如果redis中没有数据&#xff1a;数据库中的值要是最新值&#xff0c;且准备回写redis。只读缓存。读写缓存&#xff1a;①、同步直写策略&#xff1a;写数据库后也同步写redis缓存&#xff0c;缓存…