忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(5)有趣的指针
一、指针是C语言的灵魂
# include <stdio.h> int main(){
int *p; //p是变量名,int *表示p变量存放的是int类型变量的地址,p是一个指针变量
int i = 3; //p = i; 这样写是错误的
//p = 4; 这样写是错误的
p = &i; //将i变量的地址给p变量
//p保存了i的地址,因此p指向i,修改p的值不影响i的值,修改i的值也不影响p的值 return 0;
}# include <stdio.h> int main(){
int *p; //不表示定义了一个名字叫做 *p的变量
//应该这样理解:p是变量名,p变量的数据类型是 int *类型
//int *类型实际就是存放int变量地址的类型 int i = 3; p = &i; printf("*P = %d\n", *p);
printf("i = %d\n", i);
return 0;
}注释:1.如果p是个指针变量,并且p存放了普通变量i的地址,则p指向了普通变量
2.*P 完全等同于 普通变量i (有i出现的地方都可以替换成*p)指针和指针变量的区别:
1.指针就是地址,地址就是指针,地址就是内存单元的编号,所以指针就是内存单元的编号
2.指针变量存放地址的变量,也就是说指针变量是存放内存单元编号的变量
3.指针和指针变量是两个不同的概念,但是要注意通常我们叙述时会把指针变量简称为指针,实际它们的含义不一样
二、指针的重要性:
1.表示一些复杂的数据结构
2.快速的传递数据
3.使函数返回一个以上的值(函数只能返回一个值)
4.能直接访问硬件
5.能够方便的处理字符串
6.是理解面向对象语言中引用的基础
# include <stdio.h> int f(int a, int b);
void g(int * p ,int * q); int main(void){ int a = 100;
int b = 200; // a = f(a, b);
g(&a, &b);
printf("a = %d, b = %d\n", a, b); return 0;
}
//只能修改一个值
int f(int a, int b){ return 1;
}
//这样被调函数可以修改主调函数一个以上的值
void g(int * p ,int * q){
*p = 1;
*q = 2;
}
三、指针的定义
1、地址:内存单元的编号,地址是从零开始的非负整数。
2、范围:
控制总线
CPU <----> 数据总线 <-----> 内存条
地址总线
控制线控制数据传输的方向
数据线是传输数据
地址线是确定是控制哪个内存单元cup<-----> 数据总线 <-----> 内存条
一根线控制两个 0和1
两根线控制四个
n根线控制2的n次方个单元(字节)(每个单元是8位)32位机 2x10^32
1G=2X10^30B(字节)
2x10^32 ~= 2X10^30*4 所以内存最大4G3、指针:指针就是地址,地址就是指针,指针变量就是存放内存单元编号的变量。
指针本质就是一个操作受限(不能运算,只是编号)的非负整数(地址)
四、指针的分类
1、基本类型的指针
常见错误1:
# include <stdio.h> int main(void){
int *p; //p指向一个垃圾值的地址,也就是一个垃圾地址
int i = 5; *p = i; // 就是将i的值给了一个不知道的地址,这样写不对
printf("%d\n", *p); return 0;
}常见错误2:
# include <stdio.h> int main(void){
int i = 5;
int *p;
int *q; p = &i
//*q = p; 语法编译出错
//*q = *p; error q指向一个垃圾地址
q = p; // error 可以读 q里面的垃圾地址,但是不能读*q的值,没有控制权限。
printf("%d\n", *q); return 0;
}一个经典的指针程序:
# include <stdio.h> void huhuan(int i, int j);
void zhizhenhuhuan(int * a, int * b);
void huhuan3(int * a, int * b); int main(void){
int a = 3;
int b = 5; // huhuan(a, b);
// zhizhenhuhuan(&a, &b);
huhuan3(&a, &b); printf("a = %d,b = %d\n", a, b); return 0;
} void huhuan(int a, int b){ //不能完成互换,a,b是形参,单独分配内存
int t; t = a;
a = b;
b = t;
} void zhizhenhuhuan(int * a, int * b){ //不能完成互换,互换了指针的指向
int * t; t = a;
a = b;
b = t;
} void huhuan3(int * a, int * b){ //可以完成互换,传递的是地址,交换的是地址指向的值
int t; t = *a;
*a = *b;
*b = t;
}*的含义:
♥乘法 c = a*b;
♥定义指针变量 int * p;
♥取值运算符 *p
2、指针和数组的关系
一维数组名是个指针常量,它存放的是数组第一个元素地址
int a[5];
int b[5];
//a = b 是错误的 a,b都是常量# include <stdio.h> int main(void){
int a[5]; printf("%#x\n", &a[0]);
printf("%#x\n", a); return 0;
}输出结果:0x12ff6c
0x12ff6c
如果p是个指针变量,则p[i]永远等价于 *(p+i)
确定一个一维数组需要两个参数:
数组第一个元素的地址
数组的长度
//f函数可以输出任何一个一维数组的内容
# include <stdio.h> void f(int * pArr, int len){
int i;
for (i=0; i<len; i++)
printf("%d ", *(pArr+i));
printf("\n");
}
int main(void){
int a[5] = {1, 2, 3, 4, 5};
int b[6] = {-1, -2, -3, 4, 5, -6};
int c[100] = {1, 99, 22, 33}; f(a, 5); //确定一个数组:数组首地址和长度
f(b, 6);
f(c, 100); return 0;
}# include <stdio.h> void f(int * pArr, int len){
pArr[3] = 88; //pArr[3]等价于a[3]也等价于*(a+3)和*(pArr+3)
// *a==a[0]
} int main(void){
int a[6] = {1, 2, 3, 4, 5, 6}; printf("%d\n", a[3]);
f(a, 6); // a和pArr都指向数组的第一个元素
printf("%d\n", *(a+3)); return 0;
}
五、指针变量的运算
指针变量不能相加,不能相乘,也不能相除(这些运算没有意义)
如果两个指针变量指向的是同一块连续空间中得不同的存储单元,则这两个指针才可以相减(这样减才有意义)
# include <stdio.h> int main(void){
int i = 5;
int j = 10;
int * p = &i;
int * q = &j;
//此时p和q不能相减
int a[5];
p = &a[2];
q = &a[4]; printf("相减的结果为:%d\n", p-q);
//此时p和q可以相减,相减的值指p和q单元相隔的个数 return 0;
}结果为:相减的结果为:-2
六、指针变量长度
预备知识:
sizeof(数据类型);或者 sizeof(变量名);返回该数据类型所占的字节数
例如: sizeof(int) = 4 sizeof(char) = 1
# include <stdio.h> int main(void){
char ch = 'A';
int i = 90;
double x = 66.6;
char * p = &ch;
int *q = &i;
double *r = &x; printf("%d %d %d\n", sizeof(p), sizeof(q), sizeof(r));
}输出的结果:4 4 4
七、多级指针
# include <stdio.h> int main(void){
int i = 10;
int * p = &i;
int ** q = &p;
int *** r = &q; printf("i = %d\n", ***r); return 0;
}结果: i = 10
忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(5)有趣的指针的更多相关文章
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(2)准备知识
一.变量为什么必须初始化? 在回答这个问题之前,我们先来运行一段代码: #include <stdio.h> int main(){ int i; printf("i=%d\n& ...
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(3)输入输出函数
一.基本的输入和输出函数的用法 1.printf() //屏幕输出 用法: (1)printf("字符串\n"); (2)printf("输出控制符", 输出 ...
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(1)GCC介绍及C语言编译过程
一.GCC基本介绍 GCC(GNU Compiler Collection,GNU编译器套装),是一套由GNU开发的编程语言编译器.它是一套以GPL及LGPL许可证所发布的自由软件,也是GNU计划的关 ...
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(9)链表
我们至少可以通过两种结构来存储数据 数组 1.需要一整块连续的存储空间,内存中可能没有 2.插入元素,删除元素效率极低. 3.查找数据快 链表 1.查找效率低 2.不需要一块连续的内存空间 3.插入删 ...
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(8)枚举、补码
一.枚举 # include <stdio.h> enum WeekDay //定义了一个数据类型(值只能写以下值) { MonDay, TuesDay, WednesDay, Thurs ...
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(7)结构体
一.为什么需要结构体? 为了表示一些复杂的事物,而普通类型无法满足实际需求 二.什么叫结构体? 把一些基本类型组合在一起形成的一个新的复合数据类型叫做结构体. 三.如何定义一个结构体? 第一种方式: ...
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(6)动态内存分配
一.传统数组的缺点: 1.数组的长度必须事先定制,且只能是常整数,不能是变量 int len = 5; int a[len]; //error 2.传统形式定义的数组,该程序的内存程序员无法手动释放 ...
- 忙里偷闲( ˇˍˇ )闲里偷学【C语言篇】——(4)for == while ?
一.for和while等价替换 int i = 1; for (i; i<=100; i++){ sum = sum + 1; } int i = 1; while(i<=100){ su ...
- 闲里偷忙的CPU-某个kwoker进程忙
https://zhuanlan.zhihu.com/p/34311472 有一类比较特殊的CPU使用率问题,这类问题的特点是,系统平均CPU使用率很低,但是个别CPU的使用率非常高.今天借助这个真实 ...
随机推荐
- (转)Linux下使用rsync最快速删除海量文件的方法
转自 : http://www.ha97.com/4107.html 昨天遇到了要在Linux下删除海量文件的情况,需要删除数十万个文件.这个是之前的程序写的日志,增长很快,而且没什么用.这个时候,我 ...
- HDU 5389 Zero Escape (MUT#8 dp优化)
[题目链接]:pid=5389">click here~~ [题目大意]: 题意: 给出n个人的id,有两个门,每一个门有一个标号,我们记作a和b,如今我们要将n个人分成两组,进入两个 ...
- 安卓手机运行WINDOWS
http://www.pcdiy.com.tw/detail/1974 我的ZenFone 2手机可以跑Windows啦! 就在台风来袭,有人正准备去泛舟的那天,国外的XDA论坛神人则是选择让自己的Z ...
- touch、touchevent-事件总结
1.废话不多说,直接上代码,如下 package com.example.mygestrue; import android.support.v7.app.ActionBarActivity; imp ...
- Java Web学习总结(13)——JSP入门
一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写h ...
- cdn缓存
1:缓存是什么? 首先.看看没有站点没有接入CDN时.用户浏览器与server是怎样交互的: 假设中间加上一层CDN,那么用户浏览器与server的交互例如以下: client浏览器先检查是否有本地缓 ...
- 关于jsonp跨域的问题以及解决方法(跨域、同源与非同源)
什么是跨域? 想要了解跨域,首先需要了解下浏览器的同源机制: JSONP和AJAX相同,都是客户端向服务器端发送请求:给服务器端传递数据 或者 从服务器端获取数据 的方式 JSONP属于非同源策略(跨 ...
- Storm新特性之Flux
Storm新特性之Flux Flux是Storm版本号0.10.0中的新组件,主要目的是为了方便拓扑的开发与部署.原先在开发Storm拓扑的时候整个拓扑的结构都是硬编码写在代码中的,当要对其进行改动时 ...
- thinkphp5最最最最简单的ajax实例
thinkphp5最最最最简单的ajax实例 一.总结 一句话总结:页面端使用$.get()方法传递ajax请求,服务器端判断是不是ajax请求,是的话接受参数,进行逻辑处理之后向客户端返回值. 1. ...
- zoj 2724 Windows Message Queue 优先队列
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1724 题目大意: 给出两种操作,GET要求取出当前队首的元素,而PUT会输入名 ...