让你不再害怕指针

1.细说指针

  指针是一个特殊的变量, 它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容: 指针的类型、指针所指向的类型、指针的值或者叫指针所指向的内存区、 指针本身所占据的内存区。

2.指针的类型  

  最简便办法就是把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。

int *ptr;  //指针类型是int*
char *ptr; //指针类型是char*
int **ptr;//指针类型是int **
int (*ptr)[3];//指针类型是int(*)[3]
int* (*ptr)[4];//指针类型是int* (*)[4]
int (*func)(int,int); //指针类型 int(*)(int,int)

3.指针所指向类型

 当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当作什么来看看待。

 从语法上看,你只须把指针声明语句中的指针的名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。

int *ptr; //指针类型指向是int
char *ptr; //指针类型是char
int **ptr;//指针类型是int *
int (*ptr)[3];//指针类型是int()[3]
int* (*ptr)[4];//指针类型是int* ()[4]
int (*func)(int,int); //指针类型 int()(int,int)

 在指针的算术运算中, 指针所指向的类型有很大的作用 。
 指针的类型(即指针本身的类型) 和指针所指向的类型是两个概念。

4.指针的值----或者叫 指针所指向的内存区或地址   

指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型) 的一片内存区。

以后,我们说一个指针的值是 XX,就相当于说该指针指向了以 XX 为首地址的一片内存区域; 我们说一个指针指向了 某块内 存区域,就相当于说该指针的值是这块内存区域的首地址。指针所指向的内 存区和指针所指向的类型是两个完全不同 的概念。以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么? 该指针指向了哪里?(重点注意)

5.指针本身所占内存空间的大小

 只需要用sizeof函数测一下就知道了。在32位平台下,指针本身占据了4个字节的大小。

 指针本身所占的内存空间的大小,在判断指针表达式是否能够作为左值时很有用。

6.指针运算  

指针可以加上或减去一个整数。 指针的这种运算的意义和通常的数值的加减运算的意义是不一样的, 以单元为单位。

 如:

char a[20];
int *ptr = (int *)a; //强制转换并不会改变a的类型
ptr++;

 指针ptr的类型是int*,它指针想的内存空间的类型是Int,它被初始化为指向整型变量a。ptr++自加1,向前移动1一个int类型的长度,因此,ptr所指向的地址由原来的a[0],指向了a[4]。

 在比如:

#include<iostream>

using namespace std;

int main()
{
    int array[20] = { 0 };
    int *ptr = array;
    for (int i = 0; i < 20; ++i)
    {
        /* code */
        (*ptr)++; //每个单元加1
        ptr++; //向后移动
    }
    for (int i = 0; i < 20;i++)
    {
        cout << *(ptr + i) << endl;
    }
    system("pause");
    return 0;
}

 在如:

char a[20] = "you are a girl";
int *ptr = (int*)a;
ptr += 5;

 误区:

#include<iostream>
using namespace std;

int main()
{
    char a[20] = "you are a girl";
    char *p = a;
    char **ptr = &p;

    cout << p << endl;
    cout << ptr << endl;
    cout << *ptr << endl;
    cout << **ptr << endl;
    ptr++; //指向类型是char* 执行此段 即 &p + 4
    cout << ptr << endl;
    cout << *ptr << endl;
    cout << **ptr << endl;
    system("pause");
    return 0;
}

  总结,一个指针ptrold加(减)一个整数n后,结果是一个新的指针ptrnew,ptrnew 的类型和 ptrold 的类型相同,ptrnew 所指向的类型和 ptrold所指向的类型也相同 。ptrnew 的值将比 ptrold 的值增加(减少) 了 n 乘sizeof(ptrold 所指向的类型) 个字节。就是说,ptrnew 所指向的内存区将比ptrold所指向的内存区向高(低)地址方向移动了n个sizeof(ptrold 所指向的类型)个字节。

  指针不能进行加法运算,因为两个指针加减得到的结果,不知指向了哪个地方。但是两个指针可以进行减法运算。

7.运算符&和*

  &p的运算结果是一个指针,指针的类型是a的类型加个*,指针所指向的类型是a的类型,指针所指向的地址,就是a的地址。

8.指针表达式

int array[10];
int *pa;
pa = &a;
int **ptr = &pa;
*ptr = &b;
pa = array;
pa++;
char *arr[20];
char **parr = arr;
char *str;
str == *parr;
str == *(parr+1);

9.数组和指针的关系

 数组名是一个常量指针。

int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *ptr = arr;

char *str[3]={"hello world","hi,james","hello,xiaohua"}; //指针数组,每一个指针指向一个字符串的首地址
char s[80];
strcmp(s,str[0]);//等价于strcmp(s,*str);
strcmp(s,str[1]);//等价于strcmp(s,*(str+1))

10.指针与结构体的关系

11.指针与函数的关系

12.指针类型转换

  当我们初始化一个指针或给一个指针赋值时, 赋值号的左边是一个指针, 赋值号的右边是一个指针表达式。 在我们前面所举的例子中, 绝大多 数情况下, 指针的类型和指针表达式的类型是一样的, 指针所指向的类型和指针表达式所指向的类型是一样的。

float f = 12.3;
float *fptr = &f;
int *p = NULL;

  上述例子中,我们想让指针p指向f,应该怎么办?

p = &f; //是这样么?

  显然不对,因为指针p的类型是int * ,它所指向的类型是Int。而&f的结果是一个指针,其类型是float *,它所指向的类型是float。两者不一致。这样是行不通的。但是,为了实现我们的目录,我们可以尝试强制转换。

p = (int*)&f;

  这样,我们可以得出,如果有一个指针p,我们需要把它的类型和指向的类型改为TYPE *TYPE,语法格式为:(TYPE*)p;

  这样强制转换的结果是一个指针,该新指针的类型是TYPE*,它指向的类型是TYPE,它指向的地址是原指针指向的地址,而原来的指针Pde的一切属性都没有被修改。

  一个函数如果使用了指针作为参数,那么在函数调用语句的实参和形参的结合过程总,必须保证类型一致,否则要进行强制转换。

void func(char*);
int a = 123,b;
func((char*)&a);

void func(char *s){
    char c;
    c = *(s + 3);
    *(s + 3) = *(s +0);
    *(s + 0) = c;
}

  那么,可不可以把一个整数赋值给指针呢?

unsigned int a;
int *prt;
a = 2034533223;

ptr = 2034533223; //错误
ptr = a ; //错误

  正确处理方式:

prt = (int*) a;

  既然,能够把一个整数赋值给指针,那么能不能把指针里面的值当作一个整数取出来呢?

int a = 1223,b;
int *ptr = &a;
char *str;
b = (int)ptr; //把指针的值当作一个整数取出来
str = (char *)b; //把這个值赋值给str

13.指针的安全问题

char s = ‘a‘;
int *ptr;
ptr = (int*)&s;
*ptr = 1298;

 

 

 

 

  

时间: 2024-10-13 19:09:59

让你不再害怕指针的相关文章

让你不再害怕指针(转)

原文转自: 原文: (0)让你不再害怕指针--复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则: 从变量名处起,根据运算符优先级结合,一步一步分析. 下面让我们先从简单的类型开始慢慢分析吧: int p; //这是一个普通的整型变量 int *p; //首先从P 处开始,先与*结合,所以说明P 是一个指针,

【转】让你不再害怕指针——C指针详解(经典,非常详细)

前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运算符优先级结合,一步一步分析.下面让我们先从简单的类型开始慢慢分析吧: [cpp] view plain copy int p; //这是一个普通的整型变量 int *p; //首先从P 处开始,先与*结合,所以说明P 是一个指针,

让你不再害怕指针——C指针详解(经典,非常详细)

http://blog.csdn.net/soonfly/article/details/51131141 前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:从变量名处起,根据运算符优先级结合,一步一步分析.下面让我们先从简单的类型开始慢慢分析吧: [cpp] view plain copy int 

TurboGate邮件网关归档功能,让您不再害怕“万一”

俗话说:不怕一万,就怕万一!日常生活中,对于发生概率极低的事情(也就是我们常说的"万一"),如果一旦发生了,往往都会产生灾难性的后果.例如:金融危机.9.11事件.马航失联-- 对于企业来说,哪些"万一"事件会影响到企业呢?如:重要数据丢失.业务信息系统崩溃-- 对于这些风险事件,可以说,没有任何一种措施可以彻底杜绝其发生,但是企业却能通过一些工具.管理方法最大程度地降低这些风险,或者当风险事件发生后,将不良影响降到最低. 在 信息化时代的今天,电子邮件已然成为企事

git revert 让提交不再害怕

git revert 让提交不再害怕 使用了好多命令, 但对于 git revert 一直不敢怎么使用, 为什么呢? 因为 git merge 的存在. 每次 对于 git merge 的分支, 执行 git revert xxx 分支的时候总是报错. 没有细追. 今天同事恰好问道了这个问题. 于是追了一下. 主要就是对于 -m 命令. 查看了一下,其中对于 git revert -m 解释如下 -m parent-number, --mainline parent-number Usually

数组名a、数组名取地址&amp;a、数组首地址&amp;a[0]、数组指针*p

本文链接:https://blog.csdn.net/loongkingwhat/article/details/78910921 数组和指针向来就是傻傻分不清,当他们一起出现的时候就更加懵逼. 1 解析不同变量之间的区别: 数组名a: 数组名可以作为数组第一个元素的指针.我们由数组和指针的关系知道,a代表这个地址数值,它相当于一个指针,指向第一个元素(&a[0]),即指向数组的首地址.数组中的其他元素可以通过a的位移得到,此时的进阶是以数组中单个的元素类型为单位的,即a+i= & a[i

C++ Primer 学习笔记_57_类与数据抽象 --管理指针成员

复制控制 --管理指针成员 引言: 包含指针的类需要特别注意复制控制,原因是复制指针时只是复制了指针中的地址,而不会复制指针指向的对象! 将一个指针复制到另一个指针时,两个指针指向同一对象.当两个指针指向同一对象时,可能使用任一指针改变基础对象.类似地,很可能一个指针删除了一对象时,另一指针的用户还认为基础对象仍然存在.指针成员默认具有与指针对象同样的行为. 大多数C++类采用以下三种方法之一管理指针成员: 1)指针成员采取常规指针型行为:这样的类具有指针的所有缺陷但无需特殊的复制控制! 2)类

【转】有了Auto Layout,为什么你还是害怕写UITabelView的自适应布局?

Apple 算是最重视应用开发体验的公司了.从Xib到StoryBoard,从Auto Layout到Size Class,每一次的更新,都会给iOS应用的开发带来不小的便利.但是,对于绝对多数iOS攻城狮来说,我们依然还是很害怕写UITabelVIew的自适应布局.当然,害怕不是因为我们不会写,或者本身有什么特殊的技术点,而是因为太麻烦.当然,文章的后半部分,会给出相应的解决方案,毕竟本文不是为了吐槽而吐槽. UITabelView的自适应布局有多麻烦? 数据类型的不确定性:种类越多,页面越复

【C++】智能指针类和OpenCV的Ptr模板类

智能指针类 引用计数 智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count).智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象.引用计数为0时,删除对象. 其基本使用规则是: 每次创建类的新对象时,初始化指针并将引用计数置为1.当对象作为另一对象的副本而创建时,复制构造函数复制指针并增加与之相应的引用计数的值.对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数的值(如果引用计数减至0,则删除对