指针数组:

#include <stdio.h>

int main()
{

    int i;

    //这里插入一个指针,如果没有指针必须要依靠二维数组,而且会导致输出的时候比较麻烦。
    //指针指向这五个数组。 数组中每一个元素都是指针。

    char *p1[5] = {
        "We are the world!",
        "Nothin&#39;on you!",
        "Look at me now!",
        "我是中国人!",
        "ÎÒÊÇÖйúÈË£¡",
    };

    for(i = 0; i < 5; i++)
    {
        printf("%s\n", p1[i]);
    }

    return 0;
}

数组指针:

#include <stdio.h>

int main()
{

    /*
    int (*p2)[5] = {1, 2, 3, 4, 5};
    int i;

    for (i = 0; i < 5; i++);
    {
        printf("%d\n", *(p2 + i));
    }
    */

    /*
    int temp[5] = {1, 2, 3, 4, 5};
    int (*p2)[5] = temp;
        //这里的temp表示的是temp数组的第一个元素的地址
        //(因为二者本来就是一样的,但是仅仅是值一样)
    int i;

    for (i = 0; i < 5; i++);
    {
        printf("%d\n", *(p2 + i));
    }
    */

    int temp[5] = {1, 2, 3, 4, 5};
    int(*p2)[5] = &temp; //注意这里temp用了&
    int i;

    for (i = 0; i < 5; i++);
    {
        printf("%d\n", *(*p2 + i));
    }

        /*
        因为有&,所以
        1、p2为数组的地址的地址;
        2、*p2为数组的地址;
        3、*p2 + n为数组的第(n + 1)个元素的地址
        4、*(*p2)为数组第一个元素的值,*(*p2 + n)为数组的第n个元素的值
        */

    return 0;
}

二维数组与数组指针

#include <stdio.h>

int main()
{
    int array[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };

    /*
    int **p = array;
    这里不能用,因为C语言不够智能,无法识别array数组的一个元素到底代表了多少字节。
    */

    int(*p)[4] = array;

    /*
    int (*p)[3][4] = &array;
    可以这样写,但是后面的p要进行再一次的解引用,变为*(*(*p + i) + j))
    */

    int i, j;

    //这里用到了数组指针,由于(*p)[4]代表了一维数组(4个字节),而4表示了一共有4列,所以每加上一个i就是跳转到了下一行。

    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 4; j++)
            printf("%2d", *(*(p + i) + j));
        printf("\n");
    }

    return 0;
}

指针用于交换

/*
说起指针,相信很多人都不太了解,但是又想要去了解,却没有付诸实际行动。今天我就带领大家一起探秘指针的奥秘。花了一下午时间,晚上自习估计也在做这个。(还是不会,所以改了标题)
说起指针,很多人肯定会想到8上面的那个按键* ,为什么再加上一个字母就有了取地址等意思了呢?(注意:* 和输入的是连在一起的,例如int* float* 这都是合法的语法标识符,但是写法可能又变化比如int* p等等)
顾名思义,地址就是一个单位在内存条里面的存储位置。这个位置是一直存在的,不论是有没有单位去占用它的位置。(故输出时加上地址就会准确的输出地址,而这个地址我们看不懂,是一直比C还低级的语言)
交换是能体现指针的作用的最佳说明,如下:
*/

#include <stdio.h>

void swap_no(int a, int b);
void swap_yes(int* a, int* b);

int main()
{

    int a = 5, b = 3;

    printf("In main,互换前:a = %d, b = %d\n", a, b);

    swap_no(a, b);

    printf("In main,用指针互换前:a = %d, b = %d\n", a, b);

    swap_yes(&a, &b); //因为此处用到了指针,所以要求a和b都应该进行取地址才能输入到指针里面 

    printf("加指针后,In main,互换后:a = %d, b = %d\n", a, b);

    return 0;
}

void swap_no(int a, int b)
{

    int temp;

    printf("In swap_no,互换前:a = %d, b = %d\n", a, b);

    temp = a;
    a = b;
    b = temp;

    printf("In swap_no,互换后:a = %d, b = %d\n", a, b);
}

void swap_yes(int* a, int* b)
{

    int temp;

    printf("加指针后,In swap_yes,互换前:a = %d, b = %d\n", *a, *b);

    temp = *a;
    *a = *b;
    *b = temp;

    printf("加指针后,In swap_yes,互换前:a = %d, b = %d\n", *a, *b);
}

//如果不用指针那就只能达到交换函数里面的a, b 值的作用,而我们要求的是交换外层函数里面的a, b 值,所以只能通过交换地址来简洁的达到交换作用。
/*
结果如下:
In main,互换前:a = 5, b = 3
In swap_no,互换前:a = 5, b = 3
In swap_no,互换后:a = 3, b = 5
In main,用指针互换前:a = 5, b = 3
加指针后,In swap_yes,互换前:a = 5, b = 3
加指针后,In swap_yes,互换前:a = 3, b = 5
加指针后,In main,互换后:a = 3, b = 5
*/

引用类型

  • C语言中不能用

  • 引用(&)是标识符的别名

  • ··· 定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象

  • 例如:

int i, j;
int &ri = i; // 定义int引用ri,并初始化为变量i的引用。

j = 10;
ri = j; // 相当于i = j
  • 一旦一个引用被初始化后,就不能改为指向其他对象
  • 引用可以作为形参
#include <iostream>
using namespace std;

void swap(int &a, int &b);
// 引用a了,相当于a和x是一样的,这就是双向传递效果。
// 即直接对实参进行改变,而不是形参
void swap(int &a, int &b)
{
    int t = a;
    a = b;
    b = t;
}

int main(void)
{
    int x = 5, y = 10;

    swap(x, y);

    cout << x << &#39;\t&#39; << y << endl;

    return 0;
}

函数指针

//函数指针,和数组指针一样,指向函数的指针(下面的*fp)

//typedef int (*PTR_TO_FUN)(int, int);
//int calc(PTR_TO_FUN, int, int)

int add(int, int);
int sub(int, int);
int calc(int (*)(int, int), int, int);
int (*select(char))(int, int);

int add(int num1, int num2)
{
    return num1 + num2;
}
int sub(int num1, int num2)
{
    return num1 - num2;
}
int calc(int (*fp)(int, int), int num1, int num2)
{
    return (*fp)(num1, num2);
}

//这里用的话见注释。
int (*select(char op))(int, int)
{
    switch (op)
    {
    case &#39;+&#39;:return add;
    case &#39;-&#39;:return sub;
    }
}

#include <stdio.h>

int main()
{
    printf("3 + 5 = %d\n", calc(add, 3, 5)); // 这里可以用(& add),更加清晰。
    printf("3 - 5 = %d\n", calc(sub, 3, 5));


    /*
    这里可以这样写
    int num1, num2;
    char op;
    int (*fp)(int, int);

    printf("请输入一个式子(如3 + 5):");
    scanf("%d%c%d", &num1, &op, &num2);

    fp = select(op);
    printf("%d %c %d = %d\n", num1, op, num2, calc(fp, num1, num2));
    */

    return 0;
}

指针函数
说白了就是个函数
注意一点就是
不要返回局部变量的指针
补充一点,要是C语言中需要用到字符串,可以用指针来代表字符串的首字符的地址,然后即可找到完整的字符串。

某一次讲课的笔记

#include <stdio.h>

int main()
{

    //今天要介绍史上最牛逼的指针
    //一.指针的基本概念和用法
    // 1.一级指针的基本概念和用法
    // 2.二级指针的基本概念和用法
    // 3.多级指针
    //二.指针和数组的关系
    // 1.指针和一维数组的关系
    // 2.指针和二维数组的关系
    // 3.数组指针和指针数组的关系
    //三、指针和字符串的关系
    //四、指针和函数的关系
    //    函数指针
    int a = 10, b = 20;
    /*
    a和b分别储存在哪里?
    内存 -> 栈中(局部变量) -> &a, &b
    &:取地址运算符,能够求出一个变量的存储地址
    %d:十进制的方式打印地址
    %p/%x:十六进制方式打印地址
    */

    printf("a,b的地址分别为:%d, %d", &a, &b);
    /*
    打印这个地址和指针有什么关系
    指针就是地址,不能赋值,不能改变
    &a = 3214324(错误的,不能改变)

    常量:在运算过程中,值不能改变的量(每一次运行,操作系统都会重新分配,比如地址每次都在改变)
    变量:在运算过程中,值可以发生改变的量

    &a,&b:指针常量 

    指针变量:
    怎么定义一个指针变量
    基本数据类型:
    char, short, int, long, float, double 

    int* p;靠近int说明p是属于int*型,p是属于变量,*不属于变量名的一部分
    */
    //int* p1, p2, p3, p4, p5; 全部定义的都是指针变量吗? 只有p1是指针变量,其余都是int型

    //int* p1, * p2, * p3, * p4, * p5; 这个才是全部都是指针变量。

    /*
    指针变量和普通变量有什么区别
    普通变量存数值,指针变量存地址

    指针变量一定要进行初始化,只有初始化之后的指针变量才能使用。
    如果没有明确的指向,请用NULL(空指针)赋值
    已经有了明确的指向,那可以直接使用地址赋值。
    */

    //int* pa = NULL; pa不知道指向哪里,可以看作是指向内存地址为0的地方

    int* pa = &a;

    printf("pa = %d\n", pa); //打印的是a的内存地址,*&a <=> a

    /*
    修改内存
    *:解引用运算符,间接访问运算符
    后面跟一个地址,能够直接通过地址获取这块内存
    */

    //C语言修改常量,语法灵活(C++就不能)
    const int c = 300; //C是一个常量
    int* pc = &c; //在前面再加上一个const才能在C++上进行修改
    *pc = 800;
    printf("c = %d\n", c);

    int m = 1, n = 2;
    printf("sizeof(m = n) = %d, m = %d, m = %d\n", sizeof(m = n), m, n);
    printf("m = %d, n = %d", m, n); //m, n分别是多少?为什么没有变?

    //为什么是这样?
    //sizeof不是函数、sizeof是运算符
    //sizeof只会确定里面类型的大小,不会进行赋值运算。

    return 0;
}

结果:
a,b的地址分别为:8059772, 8059760pa = 8059772
c = 800
sizeof(m = n) = 4, m = 1, m = 2
m = 1, n = 2

void指针
#include <stdio.h>

int main()
{
int num = 1024;
int* pi = &num;
char* ps = "fishc";
void* pv;

pv = pi;
printf("pi:%p, pv:%p\n", pi, pv);
//这里必须强制转化,因为在void指针下解引用是没有作用的
printf("*pv:%d\n", *(int *)pv);

//这里不能使用,因为pv是1024的指针,但是以字符类型输出就不对了。
//ps = (char *)pv;

pv = ps;
printf("ps:%p, pv:%p\n", ps, pv);
printf("*pv:%s\n", (char*)pv);

return 0;

}
NULL指针
#define NULL ((void *)0)

#include <stdio.h>

int main()
{
    int* pi;
    int* p2 = NULL;

    printf("%d\n", pi);
    printf("%d\n", p2);
    /*
    这里会报错
    当你不清楚将指针初始化为什么地址时,请先请先将它初始化为NULL
    在对指针进行解引用时,先检查该指针是否为NULL
    优点:节约调试时间。
    */

    return 0;
}

以下是C++

指向常量的指针
const指针
不能通过指向常量的指针改变所指对象的指,但指针本身可以改变,可以指向另外的对象。

int a;
const int *p1 = &a; // p1是指向常量的指针
int b;
p1 = &b; // 正确,p1本身的值可以改变
*p1 = 1; // 编译时出错,不能通过p1改变所指的对象

指针类型的常量
声明指针常量,则指针本身不能改变

int a;
int *const p2 = &a;
p2 = &b; // 错误,p2是指针常量,值不能改变

this指针

  • 隐含于类的每一个非静态成员函数中。
  • 指出成员函数所操作的对象。
  • -当通过一个对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作时,就隐含使用了this指针。
  • 例如Point类的getX函数中:
    return x; 相当于 return this->x;