指针

指针

指针 ==》c 语言特有的数据类型
指针 ==》C 新的构造数据类型
指针 ==》虚拟内存地址

4G虚拟内存
OS区 0xbfffffff - 0xffffffff
栈区 8-10M
堆区 2-3G 0x990a008
静态区(静态区,常量区) main入口函数地址0x8048370
文本区 0x080480000
32位

在23位操作系统中,bss区和data区的区别
bss和data的相同点:
都用于存储静态变量和全局变量
bss和data的不同点:
bss存储的数据为未被初始化的变量:如static int a;
data存储的数据位倍数是花的变量:如static int a = 100;

64位
64位操作系统依然沿用32位的空间布局,但目前大部分操作个应用程序并不需要2^64的空间。它的虚拟地址空间为256TB(目前X86-64架构都遵循AMD的规范形式(canonical form))

在这256TB的虚拟内存空间中, 0000 0000 0000 0000 - 0000 7fff ffff ffff(128TB)为用户空间,
ffff 8000 0000 0000 - ffff ffff ffff ffff(128TB)为内核空间. 这里需要注意的是, 内核空间中有很多空洞, 越过第一个空洞后, ffff 8800 0000 0000 - ffff c7ff ffff ffff(64TB)才是直接映射物理内存的区域, 也就是说默认的PAGE_OFFSET为ffff 8800 0000 0000.

指针的概念:
指 针 是一种保存变量地址的变量,
定义格式:
<存储类型> 数据类型 *变量名称;
eg: char *pc; ===》目标内存大小1字节
short *pb; ===》目标内存大小2字节
int *pa; ===》目标内存大小4字节

练习:写代码测试以上几个数据类型指针的目标内存大小

#include <stdio.h>

int main(void)
{
    int a = 10;
    char *p = &a;
    printf("%p\n",p);
    p++;
    printf("%p\n",p);
    return 0;
}

指针的大小:
每一个指针的大小都为4字节(32位操作系统)
每一个指针的大小都为8字节(64位操作系统)
练习:
写代码验证指针的大小

#include <stdio.h>

int main(void)
{
    char a = 'a';
    char *p = &a;
    printf("%d,",sizeof(p));
    return 0;
}

与指针相关的运算符
1> 取址运算符
每个对象都有地址,单目运算符 & 通常被称为取址运算符。
将&运算符写在对象名之前,就可以得到该对象的地址。
例如:
单目运算符& &a; //取得a的地址(生成指向a的指针)
注意:
a. 取址运算符&的功能是取得对象的地址,这个地址称为指向该变量的指针。
b. 如果指针变量p保存了指向其他变量的地址的情况下,可以说 p 指向其他变量。
printf函数中表示对象地址的转换说明为: %p 。
2> 了解引用运算符(或取值运算符 或间接寻址运算符) *
对指针变量运用*运算符,就等同于它指向的变量。如果p指向a, *p就等同于a。

指针初始化

指针的初始化:
1、使用NULL初始化;
char *pc = NULL;
1.1. 什么是空指针?
空指针是一个特殊的指针值。是指可以确保没有指向任何一个对象的指针。
通常使用宏定义NULL来表示空指针常量值。
1.2. 对空指针NULL的使用
无论对方是指向什么类型的指针变量,都可以被赋值为NULL和NULL比较。
一般在定义变量的时候用NULL来初始化,在错误地使用了无效的指针时我们就可以马上发现潜在的BUGE。
1.3. NULL的本质
#define NULL ((void *)0)
2、使用变量初始化:
char c = 5;
char pc = &c; ==>变量定义和变量赋值。
===》c 属于在栈区定义的变量用于存储数据
===》pc 是c变量的实际地址,
是变量的指针符号
===》*pc 是c地址中存储的实际数据。
3、使用其他指针初始化
char c = 6;
char *pc1 = &c;
char *pc2 = pc1;
4、使用绝地地址初始化
char *pc = (char *)0x88888888;

指针的应用:
1、赋值
先定义指针: int *pa; ///野指针,小心定义
int *pa = NULL;
在给指针赋值:
int b=9,c=8 ;
pa = &b; ///将普通变量的地址赋值为指针变量
pa = &c;
获取指针关联内存区的数据:
“%d”, *pa ;///打印地址中的数据
“%p”,pa; ///打印地址的值
注意:
指针变量类型与目标类型不一致:====>point4.c
1、指针指向类型 < 目标类型
int a = 10;
char *pc = &a;
2、指针指向类型 > 目标类型 ===>point5.c
char c = ‘a’;
int *pa = &c;
指针地址范围有浪费。

指针的算数运算

运算 ==>算术运算 关系运算 赋值运算
算术运算 ==》+ - ++ –
char c[32]={‘a’,‘b’,‘c’,‘d’};
char *pc = &c[0];
pc = pc + 2;
*pc == ‘c’;
pc = pc - 1;
*pc == ‘b’;
pc++;
*pc == ‘c’;
pc++;
*pc == ‘d’;
// ++pc;
pc --;
pc == ‘c’;
pc --;
pc --;
pc == ‘a’;
注意:
1、
pc + n ==>pc本身不变,除非赋值
pc = pc +n; ===>pc 有变化
pc ++ ; =>pc本身在变化。
2、pc + n ;
>n 不是数字,是单位。
n 是pc指向数据单元的单位。
如果pc是指向char 则n每次移动n
char个字节
如果pc是指向int 则n每次移动n
int个字节
3、pc2 = pc1+5;
pc1 = &c[0];
如果: pc2 - pc1 ==?不是地址值。是两个地址之间
间隔的单元个数。
== 5 值:
不论:pc1 pc2 所指向的c数组是int 还是 char 相减
之后都是数据单元个数。

2、关系运算 ==》 > >= < <= == !=
关系运算符号对于指针变量比较的是纯地址大小/
char c[10] ={…};
char *pc1 = &c[0];
char *pc2 = &c[9];
( pc2 > pc1 ) ===>0xbf… > 0xbf… 确定边界
== 一般与NULL 比较 if( pc1 == NULL ) ///pc1不可用
!= if(NULL !=pc1 )///pc1指向有效内存。
char *pc3 = NULL;
pc3 = pc1;
if(NULL = pc3) /// 避免 if( pc3 = NULL)
{
pc3++;
}
if(pc == NULL) if(pc != NULL)
if(pc=NULL) if(pc=NULL) ///合法赋值,没错
if(NULL == pc) if(NULL != pc)
if(NULL =pc) if(NULL =pc) ///编译器错误
3、赋值运算符 = += -=
= 赋值符号主要用于给指针赋值或者初始化;
char *pc = NULL;
pc = &a;
一般要求 = 左边是指针变量,右边必须是地址或同类型变量
+= ===》 pc +=2; == pc = pc+2;
-= ===> pc -=2; == pc = pc-2;
4、const 和指针
4.1 让指针指向一个常量对象,这样可以防止该指针来修改所指向的值
4.2 将指针本身声明为常量,这样可以防止改变指针指向的位置
如:声明一个指向常量的指针p;
int age = 25;
const int p = &age;该声明指出,p指向一个const int,因此不能使用p来修改这个值,也就是说p的值为const,不能被修改。
*p+= 1; //wrong
cin >> *p; //wrong
但是p指向age,但age不是const。所以可以通过age变量来修改age的值,但是不能使用p指针来修改它。
*p = 20; //wrong
age = 20;//right
以前我们将常规变量的地址赋值给,而这里将常规变量的地址复制给指向const的指针,因此还有两种可能:将const变量的地址赋值给指向const的指针、将const的地址赋值给常规指针。然而第一种可行,第二种不可行。
const float ge = 9.80;
const float *pg = &g; //wrong
const float gm = 1.63;
float *pm = &gm; //right
对于第一种情况来说,既不能使用ge来修改值9.8,也不能使用pg来修改。C++禁止第二种情况的原因很简单——如果将gm的地址赋值给pm,则可以使用pm来修改gm的值,这使得gm的const状态很荒谬,因此C++禁止将const的地址赋值给非const指针。

数组与指针的关系

数组与指针 ==》字符数组和字符指针 字符串
====》数组指针 ===》本质是指针 只不过是数组的
====》指针数组 ===》本质是数组 只不过是指针的
数组指针:
数组定义: char c[128] ={0};
指针定义: char *pc = NULL;
数组指针关联: pc = &c[0];
pc 就是数组指针 可以表示数组的元素。
==》等价关系:
c[i] == pc[i] == *(pc +i) == (c+i);
==》不等价关系
pc 是变量可以变更
c 是数组名称是常量不能变更
指针数组 ==》数组
int a[10] ={1,2,3,4,5};
int
pa[10] ={0x111,0x222,0x333};
int a = 100;
int b = 200;
int c = 300;
int *pa[3] ={&a,&b,&c};
printf(“a = %d pa = %d”,a, *(pa[0]));

void指针:==》空指针 =》纯粹的地址
变量的定义不允许使用void类型; void a; ????多大空间
指针的定义可以使用 void 类型: void * pa; ///默认的地址空间
int a = 9;
int *pa = &a;
&pa == ?
=>pa 在哪存储 多大?
===>pa 不做调整默认在定义的范围,一般是栈区
===》所有指针都是4 字节大小 《===原因: 地址范围
定义void * 的用意可以用来表示任意地址;
int a = 8;
int* pa = &a;
void* pv = NULL;
pa == (int *)pv;
bzero(void *s,int n);
功能:给一个字符串的首地址和字符串的大小,该函数会清空这个字符串所在的内存区。
参数:s可以是任意字符串,n是字符串长度
返回值:无

#include <stdio.h>
#include <string.h>

#define SIZE sizeof(a)/sizeof(a[0])

int main(int argc,const char* argv[])
{
    int i = 0;
    char a[10] = {"asdfghj"};
    bzero(a,SIZE);
    for(i=0;i<SIZE;i++)
        printf("%c ",a[i]);
    printf("\n");
    return 0;
}

char s[128] ={“asdfaosdfjlasjdflkas”};
bzero(s,128);
===>s[128] =={0};
void *类型的指针一般用于两个地方:
1、函数传参数: void bzer(void *s ,int n);
2、函数返回值: void * memcpy(…);
===>指针在函数中的应用: 函数指针 指针函数

指针函数

指针函数:
指针函数是指带指针的函数,即本质上是一个函数,函数都有返回值类型(如果不返回,则无类型),只不过指针函数返回类型是某一类的指针。
格式: 数据类型 *函数名称(形参列表)
eg: void *memcpy(void *dest, const void *src, size_t n);
char *strcat(char *dest, const char *src);
char *strcpy(char *dest, const char *src);

指针函数内部:
栈区变量: //在作用域结束后计算机会自动帮我们实现内存的清空
全局变量
静态变量
堆区变量
常量地址

#include <stdio.h>

void *fun(void)
{
//  char *a = "nihao";  
//"nihao"字符串常量,存放于常量区,释放的时候只是将a的地址释放,但是常量区的内容没有释放
    static  int a = 10;
//  return a;
    return &a;
}

int main(int argc,const char* argv[])
{
//  char *p = NULL;
    int *p = NULL;
    p = fun();
//  printf("%s\n",p);
    printf("%d\n",*p);
    return 0;
}

函数指针:
概念: 函数指针是指向函数的指针变量。因而"函数指针"本身首先应该是指针变量,值不过该指针是指向函数。正如指针变量可以指向整型变量,字符型数组一样,在这里是指向函数。
函数指针的用途:调用函数、做函数的参数
使用函数指针的必要条件:
1、必须有一个已经存在的函数原型
int add(int a,int b);
2、定义一个函数形式的指针
int (*padd)(int,int);
函数指针的格式:
函数数据类型 (*函数指针名)(函数参数);
区分指针函数
int *fun(int a,int b); //指针函数
int * (*fun)(int a,int b); //指向指针函数的函数指针
3、函数指针与目标函数关联
padd = add;
4、使用函数指针访问函数

#include <stdio.h>

int add(int a,int b)
{
    return a+b;
}

int main(int argc,const char* argv[])
{
    int (*padd)(int,int);
    int a =5,b =9,ret = 0;
//  ret = add(a,b);
    padd = add;
    ret = padd(a,b);

    printf("%d\n",ret);

        
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值