day5 -指针
指针和指针变量
- 指针就是地址,地址就是指针
- 地址就是存放单元的编号
- 指针变量是存放地址的变量
- 指针和指针变量是两个不同的概念,但是要注意,通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样
指针热身-1
#include <stdio.h> int main(void)
{
int * p; //p是变量的名字,int * 表示p变量存放的是int变量的地址
// int *p不表示一个名字叫做p的变量
//int*p应该理解为p是变量名,p变量的数据类型是int *类型
// 所谓 int *类型实际就是存放int变量地址的类型
int i=;
int j;
p=&i;
/*
1.p保存了i的地址,因此p指向i;
2.p不是i,i也不是p,更准确的说,修改p的值不影响i的值,修改i的值也不影响p的值
3.如果一个指针变量指向了某个普通变量则
*的指针变量 就完全等同于 普通变量
例子:
如果p是个指针变量,并且p存放了普通变量i的地址
则p指向了普通变量i
*p 完全等同于 i
或者说 在所有出现*p的地方都可以替换成i
*p 就是以p的内容为地址的变量
*/
// p=i; //error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值
j = *p; //等价于j= i
printf("i=%d,j= %d",i,j);
return ;
}
指针的重要性:
- 表示一些复杂的数据结构
- 快速的传递数据
- 使函数返回一个以上的值
- 能直接访问硬件
- 能够方便出来字符串
- 是理解面向对象语言中引用的基础
总结:指针是c语言的灵魂
指针的定义
地址:内存单元的编号
从零开始的非负整数
范围:4G【0-4G】
指针:指针就是地址,地址就是指针
指针变量就是存放内存单元编号的变量,或者说指针变量就是存放地址的变量
指针的本质就是一个操作受限的非负整数
指针的分类
- 基本类型指针
- 指针和数组
- 指针和函数
- 指针和结构体
- 多级指针
经典指针程序—互换两个数字
// 互换两个数字的值
#include <stdio.h>
void huhuan_2(int * p,int * q) //*p=a *q=b
{
int t; //如果要互换*p和*q的值,则t必须定义成int,不能定义成int *,否则语法出错
t=* p ; //p是int *,*p是int
* p= * q;
* q= t;
return ;
}
/*void huhuan_1(int a,int b) //不能完成互换功能
12 {
13 int t;
14 t=a;
15 a=b;
16 b=t;
17 return ;
18 }*/
int main(void)
{
int a=;
int b=;
huhuan_2(&a,&b);
printf("%d %d\n",a,b);
return ;
}
附注:
*的含义
1.乘法
2.定义指针变量
int * p //定义了一个名字叫p的变量,int *表示p只能够存放int变量的地址
3.指针运算符
该运算符放在已经定义好的指针变量的前面
如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量
如何通过被掉函数修改主调函数普通变量的值?
1.实参必须为该普通变量的地址
2.形参必须为指针变量
3.在被掉函数中通过
*形参名
的方式就可以修改朱掉函数相关变量的值
2.指针和数组
指针和一维数组
一维数组名是个指针常量,它存放的是一维数组和第一个元素的地址
// 一维数组名是个指针常量,它存放的是一维数组和第一个元素的地址
#include <stdio.h>
int main(void)
{
int a[];
printf("%#x\n",&a[] );
printf("%#x\n",a);
return ;
}
/* 在vc6.0中的结果为:
11 0x18ff34
12 0x18ff34
下标和指针的关系
如果p是个指针变量,则 p[i]永远等价于*(p+i)
确定一个一维数组需要几个参数
需要两个参数
1.数组第一个元素的地址
2.数组的长度
#include <stdio.h>
//f函数可以输出任何一个一堆数组的内容
void f(int * p,int q)
{
int i;
// for (i=0;i<q;++i)
for (i =;i<q;++i)
printf("%d\n",*(p+i)); //*(p+i)等价于 p[i] 也等价于 a[i]也等价于*(b+i)
}
/*
p[i]的意思就是从地址p开始向后偏移i个单位后的地址空间内的值
*(p+i) 也是上面的意思
[]实际上就是个地址偏移操作符 ,c语言编译器就是把p[i]转换成*(p+i)处理的,p[i]和*(p+i)无条件等价
比如有数组int p[4]={1,2,3,4};
p就是这个数组的首地址
p[2]就是从p开始偏移2个int单位后的地址内的值 就是3
*(p+2) 这个更好理解,p+2就是在p的基础上+2个int单位的地址,那么*(p+2)就是这个地址内的值:3
*/
int main(void)
{
int a[]={,,,,}; f(a ,); //a是int *
return ;
}
#include <stdio.h>
void f(int * p, int q)
{
p[]=;
}
int main(void)
{
int a[] ={,,,,,};
printf("%d\n",a[]);
f(a ,);
printf("%d\n",a[]);
return ;
}
/*在vc6.0中的结果为
15 4
16 88
指针变量的运算
指针变量不能想加 不能想乘 不能相除
如果两个指针变量指向的是同一块连续空间中的不同存储单元 则这两个指针变量才可以相减
#include <stdio.h>
int main(void )
{
int a[];
int * p;
int * q;
p=&a[];
q=&a[];
printf("p和q所指向的单元相隔%d个单元\n",q-p);
return ;
}
//在vc6.0中的结果为:p和q所指向的单元相隔3个单元
一个指针变量到底占几个字节
假设p指向char类型变量(1个字节)
假如q指向int类型变量(4个字节)
假如r指向double类型变量(8个字节)
p,q,r本身所占的字节数是一样的
指针和二维数组
动态内存分配
传统数组的缺点:
1.数组长度必须事先指定,且只能是常整数,不能是变量 例子: int a[5] // ok int len;int a [len] //error
2.传统形式定义的数组,该数组的内存程序员无法手动释放
在一个函数运行期间,系统为该函数中所非配的内存会一直存在,直到该函数运行完毕时,该数组才会被系统释放
3.数组的长度一旦定义,其长度就不能再更改
数组的长度不能再函数运行的过程中动态的扩充或缩小
4.A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用
传统方式定义的数组不能跨函数使用
为什么需要动态分配内存
动态数组很好的解决了传统数组的这4个缺点
传统数组也叫静态数组
动态分配内存举例—动态数组的构造
molloc函数
#include <stdio.h>
#include <malloc.h>
int main(void )
{
int i = ; //分配了4个字节,静态分配
int * p=(int *)malloc(); //12行
/*
1.要使用molloc函数,必须要加malloc.h这个头文件
2.malloc函数只有一个形参,并且形参是整型
3.4表示请求系统为本程序分配4个字节
4.malloc函数只能返回第一个字节的地址
5.12行分配了8个字节,p变量占4个字节,p所指向的内存也占4个字节
6.p本身所占的内存是静态分配的,p所指向的内存是动态分配的
*/
* p =; //*p代表就是一个int变量,只不过*p这个整型变量内存分配和11行的i变量分配方式不同
freee (p);//表示把p所指向的内存给释放掉
printf("同志们好!");
return ;
}
静态内存和动态内存的比较
跨函数使用内存的问题
day5 -指针的更多相关文章
- TODO:Golang指针使用注意事项
TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++虚函数和函数指针一起使用
C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- c 数组与指针的使用注意事项
数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...
- Marshal.Copy将指针拷贝给数组
lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
- 智能指针shared_ptr的用法
为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...
随机推荐
- ExtJS4笔记 Data
The data package is what loads and saves all of the data in your application and consists of 41 clas ...
- Caffe配置简明教程 ( Ubuntu 14.04 / CUDA 7.5 / cuDNN 5.1 )
1. 前言 本教程使用的系统是Ubuntu 14.04 LTS 64-bit,使用的CUDA版本为7.5,使用的NVIDIA驱动版本为352. 如果您使用的Pascal架构显卡,如GTX1080或者新 ...
- Docker 安装部署
Docker学习笔记 一.Ubuntu Docker 安装 (1).获取最新版本Docker安装包 lyn@lyn:/data/docker$ sudo wget -qO- https://get.d ...
- Unit01-OOP-对象和类(上)
Unit01-OOP-对象和类(上) 1.什么是类?什么是对象? 1)现实生活是由很多很多对象组成的 基于对象抽出了类 2)对象:真实存在的单个的个体 类:类型.类别,代表一类个体 ...
- ubuntu 16.04 忘记root密码的处理方法
1.开机按ESC,出现如下界面 2.按回车键进入如下界面,然后选中有recovery mode的选项 3.按e进入如下界面,并找到图中红色框的recovery nomodeset,并在这一行的后面输入 ...
- 自定义view中错误:No resource identifier found for attribute X in package X
- java实现求数组中元素第二大的元素
/** * 找出数组中数第二大的值 * @param array * @date 2016-9-25 * @author shaobn */ public static void getMethod_ ...
- AJAX-----11iframe模拟ajax文件上传效果原理3
如果直接给用户提示上传成功,那么如果用户上传的文件比较大点,那么等上半天都没反映,那么用户很有可能会刷新或者关了从来等... 那么会给我们服务器带来一定的影响,所以我们可以对这方面的用户体验度进行提升 ...
- Excel应该这么玩——4、命名区域:搞定下拉框
前三篇都是讲的给Excel元素命名,本篇再介绍一种命名的使用方式:命名区域.区域是多个单元格的集合,可以是单行.单列或者类似表格的单元格矩阵,也可以是不连续的多个单元格,但很少用到.当然,一个单元格也 ...
- 说一下linux中shell的后台进程与前台进程
环境: 操作系统:archlinux; 终端模拟器:rxvt-unicode(urxvt); shell:bash; 这里所说的后台进程是指在命令行后面加一个 ampersand(&),前台进 ...