全国计算机等级考试二级教程-C语言程序设计_第8章_地址和指针

时间:2023-03-08 21:20:24

面试:

unsigned int *p1 = #
int *p2 = #

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int num = -;
unsigned int *p1 = &num;
int *p2 = &num; printf("%u,%d", *p1, *p2); system("pause");
}

输出结果:

4294967295,-1请按任意键继续. . .

//左边是指针指向内容的大小,右边是指针的大小

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int *p;
double *pb;
//左边是指针指向内容的大小,右边是指针的大小
printf("%d,%d\n", sizeof(*p), sizeof(p));
printf("%d,%d\n", sizeof(*pb), sizeof(pb)); system("pause");
}

//指针相减,如果值为正,p1在p2后面,值为负,p1在p2后面
//具体之差就意味着指针之间相隔几个元素的大小
//具体之差不是地址之差,而是地址之差除以指向元素的大小

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int a = ;
int b = ;
int *p1 = &a;
int *p2 = &b; int num = p1 - p2;
//指针相减,如果值为正,p1在p2后面,值为负,p1在p2后面
//具体之差就意味着指针之间相隔几个元素的大小
//具体之差不是地址之差,而是地址之差除以指向元素的大小
printf("%x,%x,%d", p1, p2, num); system("pause");
}

1、  若有p=a(p指向数组a),则:

np++(或p+=1),表示p指向下一元素。

n*p++与*(p++)等价。同样优先级,结合方向为自右向左。

n*(p++) 与*(++p)。

前者是先取*p的值,后使p值加1,相当于a[i++];后者是先使p加1,再取*p,相当于a[++i]。

n(*p)++表示p所指向的元素值加1,而非指针值加1。

2、 a是一个数组

int  *p=a;

p++;

p++是先引用,再自增,自增一个sizeof(指针指向的类型)的大小。

++指针在数组内部向前移动一个元素的大小

p=p+1;

指针在数组内部向前移动一个元素的大小

*p++  等价于  *(p++) ,   ++是先引用再自增

指针在数组内部向前移动一个元素的大小

++p  先自增,再引用

*(p++)  和 *(++p)的区别?

*(p++) 先引用*p,再自增p++,a[i++]

*(++p) 先自增,再引用

(*p)++   取出指针指向的内容自增一下

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main1()//p++
{
int a[] = { ,,,, ,,,,, };
int i;
int *p = a; for (i = ;i < ;i++)
{
printf("%d,%x\n", a[i], &a[i]);
} printf("%x\n", p); printf("%x\n", p++);//++就是先引用,再自增,自增一个sizeof指针指向的类型的大小 printf("%x\n", p);//++指针在数组内部向前移动一个元素的大小 system("pause");
} main2()//++p
{
int a[] = { ,,,, ,,,,, };
int i;
int *p = a; for (i = ;i < ;i++)
{
printf("%d,%x\n", a[i], &a[i]);
} printf("%x\n", p); printf("%x\n", ++p);//++就是先自增,再引用 printf("%x\n", p);//++指针在数组内部向前移动一个元素的大小 system("pause");
} main3()//p = p + 1
{
int a[] = { ,,,, ,,,,, };
int i;
int *p = a; for (i = ;i < ;i++)
{
printf("%d,%x\n", a[i], &a[i]);
} printf("%x\n", p);
p = p + ;//指针在数组内部向前移动一个元素的大小
printf("%x\n", p); system("pause");
} main4()//*p++
{
int a[] = { ,,,, ,,,,, };
int i;
int *p = a; for (i = ;i < ;i++)
{
printf("%d,%x\n", a[i], &a[i]);
} printf("%x\n", p);
printf("%d\n", *p++);//++先引用*p,再自增p++,*p=1,等价于*(p++),类似a[i++]
printf("%x\n", p);//指针在数组内部向前移动一个元素的大小
printf("%d\n", a[]); system("pause");
} main5()//*(++p)
{
int a[] = { ,,,, ,,,,, };
int i;
int *p = a; for (i = ;i < ;i++)
{
printf("%d,%x\n", a[i], &a[i]);
} printf("%x\n", p);
printf("%d\n", *(++p));//++先自增,再引用
printf("%x\n", p);
printf("%d\n", a[]); system("pause");
} main6()//(*p)++
{
int a[] = { ,,,, ,,,,, };
int i;
int *p = a; for (i = ;i < ;i++)
{
printf("%d,%x\n", a[i], &a[i]);
} printf("%x\n", p);
printf("%d\n", (*p)++);//取出指针指向的内容自增一下
printf("%x\n", p);
printf("%d\n", a[]); system("pause");
} main()//++(*p)
{
int a[] = { ,,,, ,,,,, };
int i;
int *p = a; for (i = ;i < ;i++)
{
printf("%d,%x\n", a[i], &a[i]);
} printf("%x\n", p);
printf("%d\n", ++(*p));//先自增,再引用
printf("%x\n", p);
printf("%d\n", a[]); system("pause");
}

//地址的比较没有意义,只能判断哪个地址也就是内存编号比较靠前
//不在数组,没有太大意义

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int num1 = , num2 = ;
int *p1 = &num1;
int *p2 = &num2; printf("num1=%d,*p1=%d\n", num1, *p1);
printf("num2=%d,*p2=%d\n", num2, *p2); printf("%x,%x\n", &num1, p1);
printf("%x,%x\n", &num2, p2); //地址的比较没有意义,只能判断哪个地址也就是内存编号比较靠前
//不在数组,没有太大意义
if (p1 > p2)
{
printf("p1的地址比较靠后");
}
else
{
printf("p2的地址比较靠后");
} system("pause");
}

指针比较

if (p1 == p2)为真,则p1和p2指向同一个变量

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int num = ;
int *p1 = &num;
int *p2 = &num; if (p1 == p2)
{
printf("指向同一个变量\n");
}
else
{
printf("不是指向同一个变量");
} //num,*p1,*p2三者改变其中一个,另外两个都会改变
num = ;//直接赋值
printf("%d,%d,%d\n", num, *p1, *p2); *p1 = ;//间接赋值
printf("%d,%d,%d\n", num, *p1, *p2); *p2 = ;//间接赋值
printf("%d,%d,%d\n", num, *p1, *p2); system("pause");
}

p++;//指针++,就是按照指针类型的大小,前进一个类型的大小,如果是int,前进4个字节
printf("%d", *p);//指针++,只有在数组内部才有意义

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h>
#include<windows.h> main()
{
int num = ;
int *p = &num;
p++;//指针++,就是按照指针类型的大小,前进一个类型的大小,如果是int,前进4个字节
printf("%d", *p);//指针++,只有在数组内部才有意义 system("pause");
}

int *p1 = &num;//地址的赋值
int *p2 = p1;//指针的赋值
//num,*p1,*p2一个改变,其他两个都会跟着改变

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int num = ;
int *p1 = &num;//地址的赋值
int *p2 = p1;//指针的赋值
//num,*p1,*p2一个改变,其他两个都会跟着改变 *p2 = ; printf("%d,%d,%d", num, *p1, *p2); system("pause");
}

//.c比较宽泛,所以只是警告
//.cpp就是类型不匹配
//整数与指针最好不要直接运算

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int a = ; int *p = a; *p = ;
//.c比较宽泛,所以只是警告
//.cpp就是类型不匹配
//整数与指针最好不要直接运算 system("pause");
}

//指针存储的是地址,地址是首地址,从哪里开始
//从哪里结束,由类型决定
//类型决定长度,决定如何解析

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
char ch = 'A';
int num = ;
double db = 12.5;
char *p1 = &ch;
int *p2 = &num;
double *p3 = &db; printf("%x,%x,%x\n", p1, p2, p3);
printf("%c,%d,%f\n", *p1, *p2, *p3);
//指针存储的是地址,地址是首地址,从哪里开始
//从哪里结束,由类型决定
//类型决定长度,决定如何解析 system("pause");
}

二级指针:

第一,函数内部改变外部的指针变量用到二级指针

第二,游戏外挂改变外部的指针变量

函数调用,改变原来的数据,传地址,可以根据地址改变;传数据,就无法改变(形式参数会新建一个变量,接收实际参数的值)

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> void change(int *p)
{
*p = ;
} main()
{
int num = ; int *p = &num; //change(10);传递实际参数,不会改变
//change(num);传递实际参数,不会改变
//change(*p);传递实际参数,不会改变 change(p); printf("%d", num); system("pause");
}

int *p = &num;

 #define _CRT_SECURE_NO_WARNINGS

 #include<stdio.h>
#include<stdlib.h> main()
{
int num = ;
int *p = &num;//&num是一个地址,是一个常量
//p是一个指针变量,可以存储一个地址 system("pause");
}

int * p;

int * 是数据结构。

p 是变量名字。

* p 是以 p 的内容为地址的变量。

指针:表示一些复杂的数据结构,快速的传递数据,使函数返回一个以上的值,能直接访问硬件,能够方便的处理字符串,是理解面向对象语言中引用的基础。

总结:指针是C语言的灵魂。

地址:内存单元的编号,从零开始的非负整数,范围:4G

指针:

 #include <stdio.h>
main()
{
int * p; /* int *是数据类型,所谓int *类型就是存放int变量地址的类型,表示p变量存放的是int类型变量的地址
p是变量的名字 */
int i = ; int j; p = &i; /* OK
1 p保存了i的地址,因此p指向i。
2 p不是i,i也不是p,更准确的说:修改p的值不影响i的值,修改i的值也不会影响p的值
3 如果一个指针变量指向了某个普通变量,则*指针变量 就完全等同于 普通变量
例子:如果p是个指针变量,并且p存放了普通变量i的地址,则p指向了普通变量i
*p 就完全等同于 i
或者说:在所有出现*p 的地方都可以替换成i
在所有出现i 的地方都可以替换成*p
*p 就是以 p 的内容为地址的变量
*/ //p = i; // ERROR,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值 //p = 55; // ERROR,原因同上 j = *p; //等价于j=i printf("i=%d,j=%d,*p=%d\n", i, j, *p);
}

输出格式:

i=3,j=3,*p=3
请按任意键继续. . .

a b 互换功能

不能完成互换功能

 #include <stdio.h>
void huhuan(int a, int b) /*不能完成互换功能*/
{
int t;
t = a;
a = b;
b = t; return;
}
main()
{
int a = ;
int b = ; huhuan(a, b); printf("a=%d,b=%d", a, b);
}

可以完成互换功能

p 是 int *,* p 是 int

 #include <stdio.h>
void huhuan1(int * p, int * q)
{
int t; /* 如果要互换*p和*q的值,则t必须定义成int,不能定义为int*,否则语法出错 */ t = *p; /* p是int *,* p int */
*p = *q;
*q = t;
}
main()
{
int a = ;
int b = ; huhuan1(&a, &b); /*
huhuan1(*p, *q);错误
huhuan1(a, b);错误
*/ printf("a=%d,b=%d", a, b);
}

* 的含义

1 乘法

2 定义指针变量

出现在定义语句,代表定义了一个指针变量。

int * p;

定义了一个名字叫 p 的变量,int * 表示 p 只能存放 int 变量的地址

3 指针运算符,间址运算符

出现在执行语句,代表引用当前指针变量的内容。

该运算符放在已经定义好的指针变量的前面

如果 p 是一个已经定义好的指针变量

则 * p 表示以 p 的内容为地址的变量

* 与 & 是逆预算

* 间址运算符,求当前地址的内容、元素

& 地址运算符,求当前内容、元素的地址

a[0]a[1]
a[2]a[3]
a[4]

11   22    33   44    55

p              q

指针内容相减:

* q - * p = 22;

指针相减:

q - p = 2;

如何通过被调函数修改主调函数普通变量的值

1 实参必须为该普通变量的地址

2 形参必须为指针变量

3 在被调函数中通过

* 形参名 = ...

的方式就可以修改主调函数相关变量的值

 #include <stdio.h>
main()
{
int * p; /*建议写这个*/
int *p; /*都一样*/
int* p; /*都一样*/
int*p; /*都一样*/
}

8.1 用指针指向两个变量,通过指针运算选出值小的那个数。

 #include <stdio.h>
main()
{
int a, b, min, *pa, *pb, *pmin;
pa = &a;
pb = &b;
pmin = &min;
scanf("%d %d", pa, pb);
printf("a=%d,b=%d\n", a, b); *pmin = *pa;
if (*pa > * pb)
{
*pmin = *pb;
}
printf("min=%d\n", min);
}

8.2 编写函数 myadd(int * a, int * b) ,函数中把指针 a 和 b 所指的存储单元中的两个值相加,然后将和值作为函数值返回。在主函数中输入两个数给变量,把变量地址作为实参,传送给对应形参。

 #include <stdio.h>
int myadd(int * a, int * b)
{
int sum;
sum = *a + *b;
return sum;
} main()
{
int x, y, z;
printf("Enter x,y:");
scanf("%d %d", &x, &y);
z = myadd(&x, &y);
printf("%d+%d=%d\n", x, y, z);
}

8.3 调用 swap 函数,交换主函数中变量 x 和 y 中的数据。

 #include <stdio.h>
void swap(int *, int *);
main()
{
int x = , y = ;
printf("(1)x=%d y=%d\n", x, y);
swap(&x, &y);
printf("(4)x=%d y=%d\n", x, y);
} void swap(int * a, int * b)
{
int t;
printf("(2)a=%d b=%d\n", *a, *b);
t = *a;
*a = *b;
*b = t;
printf("(3)a=%d y=%d\n", *a, *b);
}

8.4 编写函数 order(int * a, int * b) ,使调用函数中的第一个实参总是存放两个数中的较小的数,第二个参数存放两个数中较大的数。

 #include <stdio.h>
void swap(int * x1, int * x2)
{
int t;
t = *x1;
*x1 = *x2;
*x2 = t;
} void order(int * a, int * b)
{
if (*a > * b)
{
swap(a, b);
}
} main()
{
int x, y;
printf("Enter x,y:");
scanf("%d %d", &x, &y);
printf("x=%d y=%d\n", x, y);
order(&x, &y);
printf("x=%d y=%d\n", x, y);
}

8.5 以下函数把主函数中变量 i 和 j 中存放较大数的那个地址作为函数值传回。

 #include <stdio.h>
int * fun(int *, int *); /* 函数说明语句 */
main()
{
int * p, i, j;
printf("Enter two number:");
scanf("%d %d", &i, &j);
p = fun(&i, &j); /* p将得到i或j的地址 */
printf("i=%d,j=%d,* p=%d\n", i, j, *p);
} int * fun(int * a, int * b)
{
if (*a > * b)
{
return a;
}
return b;
}

8.6 请编写程序,其功能是对传送过来的两个浮点数求出和值与差值,并通过形参传送回调用函数。

 #include "Stdio.h"
void f(float x, float y, float *ps, float *pd)
{
*ps = x + y;
*pd = x - y;
}
main()
{
float x, y, sum, diff;
printf("input x y=?\n");
scanf("%f %f", &x, &y);
f(x, y, &sum, &diff);
printf("%f+%f=%f %f-%f=%f", x, y, sum, x, y, diff);
}

8.7 请编写函数,对传送过来的三个数选出最大数和最小数,并通过形参传回调用函数。

 #include "Stdio.h"
void f(int a, int b, int c, int *pmax, int *pmin)
{
*pmax = *pmin = a;
if (*pmax > b)
{
*pmin = b;
}
if (*pmin < b)
{
*pmax = b;
}
if (*pmax > c)
{
*pmin = c;
}
if (*pmin < c)
{
*pmax = c;
}
}
main()
{
int a, b, c, max, min;
printf("input a b c=?\n");
scanf("%d %d %d", &a, &b, &c);
f(a, b, c, &max, &min);
printf("max=%d,min=%d", max, min);
}