指针的用法

大家都应该知道, 指针是个什么玩意儿, 它就是用来存另一个变量的地址的。这玩意儿在程序中容易引起不易察觉的错误, 而且会给调试带来莫大的困难。 尽管如此,它现在依然存在着, 这就从另一方面说明了, 它的功能爆表。 在实现链式存储, 图, 树, 森林时, 大都要用指针。 不仅如此, 在访问多维数组,函数参数传递时, 也多用指针。下面给出指针的一些常用的用法代码。


指针的用法指针的用法

/*指针的声明及一般用法*/
/*________________________________________________________________*/ 
//声明:
int a;
int *p=&a;

int a;
int *p;
p=&a;

#include<stdio.h>
int main()
{
    int a, b;
    int *ipointer1, *ipointer2;
    scanf("%d%d", &a, &b);
    ipointer1 = &a;
    ipointer2 = &b;
    printf("The number is:%d %dn", *ipointer1, *pointer2);
} 

#include<stdio.h>
int main()
{
    int *p, q;
    p=&q;
    scanf("%d", p);//另类写法。 
    printf("%dn", q);
    return 0;
}

//&*和*&的区别, &和*的优先级相同。运算顺序从左向右。
#include<stdio.h>
int main()
{
    int i;
    int *p;
    scanf("%d", &i);
    p=&i;
    printf("%dn", *&i);
    printf("%dn", i);
    printf("%dn", *p);
    printf("%dn", &*p);
    return 0;
} 

//指针的自增自减。 
#include<stdio.h>
int main()
{
    int i;
    int *p;//将变量i的地址赋给指针变量。 
    scanf("%d", &i);
    p=&i;
    printf("%dn", p);
    p++;//指针变量加1, 这里的加 1 并不代表一个字节与*p的类型有关。 
    printf("%dn", p);
    return 0;
} 

//一维数组与指针
int *p, a[10];
p=&a;

int *p, a[10];
p=&a[0];

#include<stdio.h>
int main()
{
    int *p, *q, a[5], b[5], i;
    p=&a[0];
    q=b;//数组名就代表地址。 
    for(i=0; i<5; i++)
    scanf("%d", &a[i]);
    for(i=0; i<5; i++)
    scanf("%d", &b[i]);
    for(i=0; i<5; i++)
    printf("%5d", *(p+i));
    printf("n");
    for(i=0; i<5; i++)
    printf("%5d", *(q+i));
    return 0;
}
#include<stdio.h>
int main()
{
    int *p, *q, a[5], b[5], i;
    p=&a[0];
    q=b;
    for(i=0; i<5; i++)
    scanf("%d", p++);
    for(i=0; i<5; i++)
    scanf("%d", q++);
    p=a;//使指针变量p,q 重新指向数组起始位置。 
    q=b;
    for(i=0;i<5; i++)
    printf("%5d", *p++);
    printf("n");
    printf("%5d", *q++);
    return 0;
} 
//二维数组与指针。 
#include<stdio.h>
int main()
{
    int a[3][5], i, j;
    for(i=0; i<3; i++)
    {
        for(j=0; j<5; j++)
        scanf("%d", a[i]+j);
    }
    for(i=0; i<3; i++)
    {
        for(j=0; j<5; j++)
        printf("%5d", *(a[i]+j));
        printf("n");
    }
    return 0;
}

//
#include<stdio.h>
int main()
{
    int a[3][5], i, j, *p;
    p=a[0];
    for(i=0; i<3; i++)
    {
        for(j=0; j<5; j++)
        scanf("%d", p++);
    }
}
p=a[0];
for(i=0; i<3; i++)
{
    for(j=0; j<5; j++)
    printf("%5d", *p++);
    printf("n");
}

#include<stdio.h>
int main()
{
    int a[3][5], i, j, (*p)[5];
    p=&a[0];
    for(i=0; i<3; i++)        //控制二维数组的行数。 
    for(j=0; j<5; j++)       //控制二维数组的列数。 
    scanf("%d", (*(p+i))+j); //为二维数组中的元素赋值。 
    p=&a[1];                //*p为第一个元素的地址。 
    for(j=0; j<5; j++)
    printf("%5d", *((*p)+j));//输出二维数组中的元素。 
    printf("n");
    return 0;
}
#include<stdio.h>
int main()
{
    int a[3][5], i, j;
    for(i=0; i<3; i++)
    for(j=0; j<5; j++)
    scanf("%d", *(a+i)+j);
    for(j=0; j<5; j++)
    printf("%5d", *(*(a)+j));
    printf("n");
    return 0;
}

//
#include<stdio.h>
int main()
{
    char str1[]="you are beautiful", str2[30], *p1, *p2;
    p1 = str1;
    p2 = str2;
    while(*p1!='')
    {
        *p2 = *p1;
        p1++;
        p2++;
    }
    *p2='';
    printf("Now the string2 is:n");
    puts(str2);
    return 0;
}

View Code
上面的代码只是给出了,指针的一般用法。 如果你想比较深入的理解一下指针是什么鬼, 下面的文字也许对你有些帮助。

首先给出一个警告: 一定要在对指针应用解除引用运算符(*)之前, 将指针初始化为一个确定的, 适当的地址。 -----这是关于使用指针的金科玉律。

误用指针的原因:

在C++中创建指针时, 计算机只分配了用来存放地址的内存, 而没有分配用来存储指针所指向的数据的内存。 为数据提供空间是一个独立的步骤, 而忽略这一步骤, 就可能带啦灾难性的bug。

//错误代码, 请勿模仿。 
int* p;
*p = 5;

上面的 p 的确是一个指针, 但是并不知道它指向哪里去了? 上述代码没有将地址赋给 p 。 那么 5 放到了哪里去了呢?----------》 鬼知道 。 由于 p 指向的地方不知道在哪里。 (没准是你的程序中关键代码的地址) 。 如果是这样, 就可能会导致一些最隐匿, 最难以跟踪的bug。

空指针: C++确保空指针不会指向有效的数据, 因此它常被表示运算符或函数失败(如果成功, 它们将返回一个有用的指针)。

空指针的声明方法:

int *p1 = nullptr;

int *p2 = 0;

int *p3=NULL

//上述三种声明方式等价。

事实上, 数组名和指针是差不多的,编译器在编译数组时, 会把数组编译成指针的形式。

a[i] 会被编译成 *(a+i)
//你知道的, 数组的首地址相当于指针,
//而 i 的值是编译器会根据数组的类型
//而定的。 
而一个指针变量, 如果让它指向一个数组首地址
也可以用数组的形式来访问数组元素。
int a[3]={1, 2, 10}
int*p = a;//*p = &a[0]
cout<<p[0]<<endl;
cout<<p[1]<<endl;

当然, 数组名和指针还是有区别的。 区别一: 可以修改指针的值, 因为指针是指针变量。 但是数组名是常量, 不能更改!。 区别二: 对数组应用sizeof运算符得到的是数组的长度, 而对指针应用sizeof的得到的是指针的长度。

数组的地址:

其实对数组取地址时, 数组名也不会完全被解释为数组的地址。 数组名被解释为其第一个元素的地址, 而对数组名应用地址运算符时, 得到的是整个数组的地址:

int a[10];
cout<<a<<endl;//displays &a[0]
cout<<&a<<endl;//displays address of whole array
//从数值上说, 这两个地址相同, 但是从概念上说缺有区别
//&a[0] 是 一个4字节的内存地址(即:告诉计算机要4个字节)。
//&a 是一个40字节的内存地址(即:告诉计算机要40个字节的空间)
//数组地址的这个特点为多维数组实现提供了方便。

void*指针:

void是一种特殊的指针类型,可以存放任意对象的地址(如: int型, double型, char型, 函数形, 结构体型, 等)。一个void指针存放着一个地址, 这一点和其他指针类型类似。 不同的是我们对该地址中到底是什么类型的对象并不了解。因此不能直接操作void指针所指的对象。 但是可以比较它和别的指针的大小, 作为函数的输入输出, 或者赋值给另外一个void

指向指针的引用:

int i=42;

int *p; // p是一个int型的指针

int *&r = p; //r是一个对指针p的引用.

r=&i; //r引用了一个指针,因此给r赋值&i就是令p指向i。

*r = 0; //解引用r得到 i,也就是p指向的对象, 并将i的值改为0

下面是一个关于指针的程序的简单分析:

#include<cstdio>
#include<iostream>
using namespace std;

int fun(int *data)
{
    return (*data)++;
} 

int main()
{
    int data = 55;
    cout << fun(&data) << endl;
    cout << data <<endl;
    data = fun(&data);
    cout << data <<endl;
    return 0;
}

本程序输出的是 55 56 56

是不是感到很神奇呢? 分析此程序可以知道 形参是指针类型的, 所以它是可以改变main()里的data的值的。 第一次调用fun()时, data=55, 然后返回 data 给cout输出流(此时值为55) 相当于赋值给另一个变量了(这才是输出的值), 然后 data+1 也即是: main()中的data+1, 此时data = 56. 所以第二次输出为56. 然后 是同样的 data = fun(&data) 这是关键的一句。 fun()函数返回 56, 然后 data+1 = 57 然后是 data = fun()的值, 由于fun()返回的值是56, 所以57被覆盖啦。因此第三次data输出 56. 建议上机调试此程序,以便更深入的理解。 提示: 不要在DEV C++里调试, 这个编译器的调试软件版本较老,调试此程序时可能有误!建议在 VS2010或更高版本上调试。

下面是关于一个指针的引用的示例:

#include<iostream>
int main()
{
    using namespace std;
    int rats = 101;
    int *pt = &rats;
    int &rodents = *pt;  // 在声明的时候, 将rodents初始化为 *pt 
    int bunnies = 50;    // 使得rodents指向了 rats。而后不再随 
    pt = &bunnies;        //*pt的改变而改变。 
    cout << "rats = "<< rats << endl;
    cout << "*pt = " << *pt << endl;
    cout << "rodents = " << rodents << endl;
    cout << "bunnies = " << bunnies << endl;
    cout << "rats's address = " << &rats << endl;
    cout << "rodents's address = " << &rodents << endl;
    cout << "*pt's address = " << pt << endl;
    return 0;
}

以上现象出现的原因是, 引用必须初始化,而且一旦初始化,就不再改变!

常见的因指针误用导致的存储器错误

原文链接: https://www.cnblogs.com/acm1314/p/4509141.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/216293

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月13日 上午9:21
下一篇 2023年2月13日 上午9:23

相关推荐