全国计算机等级考试二级教程-C语言程序设计_第8章_地址和指针
面试:
unsigned int *p1 = #
int *p2 = #
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> main()
{
int num = -;
unsigned int *p1 = #
int *p2 = # 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 = #
int *p2 = # 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 = #
p++;//指针++,就是按照指针类型的大小,前进一个类型的大小,如果是int,前进4个字节
printf("%d", *p);//指针++,只有在数组内部才有意义 system("pause");
}
int *p1 = #//地址的赋值
int *p2 = p1;//指针的赋值
//num,*p1,*p2一个改变,其他两个都会跟着改变
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> main()
{
int num = ;
int *p1 = #//地址的赋值
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 = #
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 = # //change(10);传递实际参数,不会改变
//change(num);传递实际参数,不会改变
//change(*p);传递实际参数,不会改变 change(p); printf("%d", num); system("pause");
}
int *p = #
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h>
#include<stdlib.h> main()
{
int num = ;
int *p = #//&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);
}
全国计算机等级考试二级教程-C语言程序设计_第8章_地址和指针的更多相关文章
- 全国计算机等级考试二级教程-C语言程序设计_第14章_结构体、共用体和用户定义类型
函数的返回值是结构体类型 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> struct ...
- 全国计算机等级考试二级教程-C语言程序设计_第4章_选择结构
switch什么时候用break,什么时候不用break 调用break:一次执行一个分支,输入一个数据,对应一个级别 不调用break:连续执行多个分支 if...else 可以处理任何情况,大于小 ...
- 全国计算机等级考试二级教程-C语言程序设计_第15章_位运算
位运算,不适用于实数,仅仅适用于整数.字符. C语言的位运算只能操作整数.字符,实数是指数方式表示的,不适用于位运算. #define _CRT_SECURE_NO_WARNINGS #include ...
- 全国计算机等级考试二级教程-C语言程序设计_第9章_数组
四维数组,可用于航天卫星,三维+时间 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> ...
- 全国计算机等级考试二级教程-C语言程序设计_第10章_字符串
字符型指针数组 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> //参数中,int a ...
- 全国计算机等级考试二级教程-C语言程序设计_第5章_循环结构
for循环结构的嵌套 外层循环每循环一次,内层循环会完整循环一次. 外层循环是竖. 内层循环是横. for, do...while, while的选择: 如果有固定次数,如阶乘! ,判断素数,用 fo ...
- 全国计算机等级考试二级教程-C语言程序设计_第3章_顺序结构
1输入两个整数给变量x和y:然后输出x和y:在交换x和y中的值后,在输出x和y. #include <stdio.h> main() { int x, y, t; printf(" ...
- 全国计算机等级考试二级教程-C语言程序设计_第2章_C程序设计的初步知识
正负号与被除数一致. 3 % (-5) == 3 (-3) % 5 == -3 不用求余运算符,求出余数. int x, y; 答:x - x / y * y; const int i = 10; c ...
- 全国计算机等级考试二级教程-C语言程序设计_第7章_函数
函数执行,从右到左执行 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> main() ...
随机推荐
- SQL Server dbcc checkdb 做了什么。
第一步: 读取系统元数据.读完这些数据后dbcc checkdb 就知道自己要检测的是一个怎样的数据库了.如果在这一步就出错了.dbcc 就直接出错 了.不会再运行下去. 第二步: 在dbcc che ...
- PowerDesigner15在生成SQL时报错Generation aborted due to errors detected during the verification of the mod
转载: http://blog.csdn.net/successful555/article/details/7582154 PowerDesigner中如何设置字符编码为GBK或者GB2312 ht ...
- USB Mass Storage大容量存储的基本知识
http://www.crifan.com/files/doc/docbook/usb_disk_driver/release/htmls/ch02_msc_basic.html 目录 2.1. US ...
- ARM和X86功耗差别的深层原因探讨
ARM和X86功耗差别的深层原因探讨 ARM和X86功耗的差别一直是个很热的话题.ARM可以做的很低,甚至1瓦都不到.而X86服务器的芯片可以达到100-200瓦,就算是嵌入式处理器Atom系列也需要 ...
- MFC永久窗口对象与临时窗口对象
这篇讲得很清楚,就转过来了,原文如下: 因项目需要,最近在学习MFC,下午在一篇教程中提到了临时窗口.永久窗口,作者让读者自行查阅MSDN,了解临时窗口与永久窗口的概念,出于好奇,出于方便,直接百度一 ...
- 【hihocoder 1249 Xiongnu's Land】线性扫描
2015区域赛北京赛区的三水,当时在赛场上没做出的原因是复杂度分析不正确导致把方法想复杂了.近来复习复杂度分析,觉得不能只是笼统地看渐进复杂度(big-O),更应根据算法的伪码计算真正的以基本操作数为 ...
- Python OpenGL学习(1): 环境配置及错误篇
系统环境是:Ubuntu 14.04 个人首次接触OpenGL,学到哪就写到哪. 1.模块安装: sudo apt-get install python-openglpip install PyOpe ...
- 启动Tomcat自动加载(运行)类
其实这是紧跟着我上次写的java计时器Timer的,因为Timer的测试类写好后,不可能要通过什么东西去触发,对已经存在的时间点进行监控 所以,在启动项目是自动运行此类 方法如下: 一.在web.xm ...
- 【OpenCV新手教程之十一】 形态学图像处理(二):开运算、闭运算、形态学梯度、顶帽、黑帽合辑
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/23184547 作者:毛星云(浅墨) ...
- paip.navicat form mysql导入文本文件时CPU占用100%的解决
paip.navicat form mysql导入文本文件时CPU占用100%的解决 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:h ...