IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++二级指针 -> 正文阅读

[C++知识库]C++二级指针

二级指针也是一个普通的指针变量,只是它里面保存的值是另外一个一级指针的地址定义:

int guizi1 = 888;

int *guizi2 = &guizi1;??? //1 级指针,保存 guizi1 的地址 int **liujian = &guizi2; //2 级指针,保存 guizi2 的地址,guizi2 本身是一个一级指针变量

// demo 8-12.c

#include <stdio.h>

#include <stdlib.h>

int main(void){

int guizi2 = 888;???? //存枪的第 2 个柜子

int *guizi1 = &guizi2;???? //存第 2 个柜子地址的第一个柜子

int **liujian = &guizi1; //手握第一个柜子地址的刘建

printf("刘建打开第一个柜子,获得第二个柜子的地址:0x%p\n", *liujian);

printf("guizi2 的地址:0x%p\n", &guizi2);

int *tmp;

tmp = *liujian;

printf("访问第二个柜子的地址,拿到枪:%d\n", *tmp);

printf("刘建一步到位拿到枪:%d\n", **liujian); //缩写成 **liujian

system("pause");

return 0;

}

二级指针的用途:

1.普通指针可以将变量通过参数“带入”函数内部,但没办法将内部变量“带出”函数

2.二级指针可以不但可以将变量通过参数函数内部,也可以将函数内部变量“带出”到函数外部。

#include <stdio.h> 
#include <stdlib.h>
void swap(int *a, int *b){
int tmp =*a; 
*a= *b;
*b= tmp;
}
void boy_home(int **meipo){ 
static int boy = 23;
*meipo = &boy;
}
int main(void){
//int x=10, y=100;
//swap(&x, &y);
//printf("x=%d, y=%d\n", x, y); 
int *meipo = NULL; 
boy_home(&meipo);
 printf("boy: %d\n", *meipo); 
system("pause"); 
return 0;
}

?项目精讲-多级指针的定义、使用

1. 可以定义多级指针指向次一级指针比如:

int guizi1 = 888;

int *guizi2 = &guizi1; //普通指针

int **guizi3 = &guizi2;?? //二级指向一级

int ***guizi4 = &guizi3; //三级指向二级

int ****guizi5 = &guizi4;????? //四级指向三级

……

// demo 8-14.c

#include <stdio.h>

#include <stdlib.h>

int main(void){

int guizi1 = 888;

int *guizi2 = &guizi1;? //普通指针

int **guizi3 = &guizi2;??? //二级指向一级

int ***guizi4 = &guizi3;?? //三级指向二级

int ****guizi5 = &guizi4; //四级指向三级

printf("柜子 2 拿枪: %d\n", *guizi2);

printf("柜子 3 拿枪: %d\n", **guizi3); printf("柜子 4 拿枪: %d\n", ***guizi4);

printf("柜子 5 拿枪: %d\n", ****guizi5);

system("pause");

return 0;

}

指针和数组的纠缠

1. 指针表示法和数组表示法

数组完全可以使用指针来访问, days[3] 和 *(days+3) 等同

#include <stdio.h>
#include <stdlib.h>
void print_months1(int days[], int	months){
 int index = 0; 
for (index = 0; index < months; index++){
//数组表示法
	printf("Month	%2d	has	%d	days.\n", index+1, days[index]);
//指针表示法
	//printf("Month	%2d	has	%d	days.\n", index+1, *(days+index));
} }

void print_months2(int *days, int months){ 
    int index = 0; 

    for (index = 0; index < months; index++){
//指针表示表示法
	printf("Month	%2d	has	%d	days.\n", index+1, *(days+index));
//数组表示法
	printf("Month	%2d	has	%d	days.\n", index+1, days[index]);
} }

int main(void)
{
    int days[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    /*int index = 0; 
    for (index = 0; index < 12; index++){
    //数组表示法
	//printf("Month	%2d	has	%d	days.\n", index+1, days[index]);
    //指针表示法
	    printf("Month	%2d	has	%d	days.\n", index+1, *days+index);
}*/
        print_months1(days, 6); //print_months2(days, 12);
    system("pause");
 return 0;
}

2. 存储指针的数组

定义:类型 *指针数组名[元素个数] ;

// demo 8-16.c
#include <stdio.h>
 #include <stdlib.h>
int main(void)
{ 
    int girls[4][3]={{173, 158, 166},
                     {168, 155, 171},
                     {163, 164, 165},
                     {163, 164, 172}};
	//int x1,y1,	x2,y2;

    int *qishou[2];//定义一个有两个元素的指针数组,每个元素都是一个指针变量
        if(girls[0][0] > girls[0][1]){
             qishou[0] = &girls[0][0]; 
             qishou[1] = &girls[0][1];
        }else { 
             qishou[0] = &girls[0][1]; 
             qishou[1] = &girls[0][0];
}
    for(int i=2; i<12; i++){ 
        //girls[i/3][i%3] 
        if(*qishou[1] >= girls[i/3][i%3]){ 
            continue;
        }

//候选者高于第二位棋手候选女兵
//1.候选者比"冠军"矮
     if(girls[i/3][i%3] <= *qishou[0]){ 
        qishou[1] = &girls[i/3][i%3];
    }else { //2.候选者比"冠军"高
        qishou[1] = qishou[0]; 
        qishou[0] = &girls[i/3][i%3];
}
    } 
        printf("最高女兵的身高: %d , 次高女兵的身高: %d\n", *qishou[0], *qishou[1]);
        system("pause");
        return 0;
}

指针和二维数组

1. 指向数组的指针 int (*p)[3]; //定义一个指向三个成员的数组的指针

访问元素的两种方式: 数组法: (*p)[j] 指针法: *((*p)+j

#include <stdio.h>
#include <stdlib.h>
int main()
{
/*据同学们报告,A 栋学生楼有学生用高倍望眼镜偷看别人洗澡,
宿管办领导决定逐个宿舍排查,得到的线报是 A0 到 A3 宿舍的
某个子最矮的男生。
*/
int A[4][3]={{173, 158, 166},
             {168, 155, 171}, 
             {163, 164, 165},
             {163, 164, 172}};

int (*p)[3]; //定义一个指向三个成员的数组的指针
int * boy = NULL;

p = &A[0];

//第一种 数组下标法
/*for(int i=0; i<4; i++){
    for(int j=0; j<3; j++){
        printf(" %d", (*p)[j]); //(*p) 等同于 a[0] ,a[0][0]等同于 (*p)[0]
}
    printf("\n");
    p++;
}*/
    boy = &(*p)[0];
//boy = (*p);
//第二种 指针访问法 //int a[3]; int * p ; p = a; 数组成员: *p *(p+1) *(p+2)
for(int i=0; i<4; i++){
    for(int j=0; j<3; j++){
        printf(" %d", *((*p)+j));
               if( *boy > *((*p)+j)){
                    boy = (*p)+j;
                }
    }
        printf("\n");
            p++;
}
    printf("偷窥的学生是: %d\n", *boy);
    system("pause");
    return 0;
}

使用普通指针访问二维数组

int A[4][3];

int *p;

//定义一个指针 p = A[0]; 或者 p=&A[0][0];

访问元素的两种方式:

#include <stdio.h>
#include <stdlib.h>
int main()
{
/*据同学们报告,A 栋学生楼有学生用高倍望眼镜偷看别人洗澡,
宿管办领导决定逐个宿舍排查,得到的线报是 A0 到 A3 宿舍的
某个子最矮的男生。
*/
int A[4][3]={{173, 158, 166},
             {168, 155, 171},
             {163, 164, 165},
             {163, 164, 172}};
int *boy = NULL;//坏男孩
int *p =NULL; //定义指针,用以遍历二维数组

//p = A[0];

p = &A[0][0];
boy = p;

for(int i=1; i<4*3; i++,p++){
    if(*boy > *p){ //*p 可以替换成 A[i/3][i%3]
        boy = p;
    }
}
printf("偷窥的学生是: %d\n", *boy);
//2.根据指针计算下标
int pos = boy - A[0];

printf("index: %d\n", pos);

printf("位于 A[%d] 宿舍\n", pos/3);

printf("是第 %d 个成员\n", pos%3);

system("pause");
return 0;
}

项目精讲-“我们不一样“之数组与指针的区别

数组:数组是用于储存多个相同类型数据的集合。

指针:指针是一个变量,但是它和普通变量不一样,它存放的是其它变量在内存中的地址。

1. 赋值

数组:只能一个一个元素的赋值或拷贝

指针:指针变量可以相互赋值

2. 表示范围

数组有效范围就是其空间的范围,数组名使用下表引用元素,不能指向别的数组

指针可以指向任何地址,但是不能随意访问,必须依附在变量有效范围之内

3. sizeof 数组:

数组所占存储空间的内存:sizeof(数组名) 数组的大小:sizeof(数组名)/sizeof(数据类型) 指针: 在 32 位平台下,无论指针的类型是什么,sizeof(指针名)都是

4. 在 64 位平台下,无论指针的类型是什么,sizeof(指针名)都是 8.

指针数组和数组指针

针指数组:

int *qishou[2];//定义一个有两个元素的指针数组,每个元素都是一个指针变量

int girl1= 167;

int girl2 = 171;

qishou[0] = &girl1;

qishou[1] = &girl2;

数组指针:

int (*p)[3]; //定义一个指向三个成员的数组的指针

访问元素的两种方式:

int A[4][3]={{173, 158, 166},

??????????????????{168, 155, 171},

??????????????????{163, 164, 165},

??????????????????{163, 164, 172}};

??????????? ? ?p = &A[0];

数组法: (*p)[j]

指针法: *((*p)+j)

传参

数组传参时,会退化为指针!

(1)退化的意义:C 语言只会以值拷贝的方式传递参数,参数传递时,如果只拷贝整个数 组,效率会大大降低,并且在参数位于栈上,太大的数组拷贝将会导致栈溢出。

(2)因此,C 语言将数组的传参进行了退化。将整个数组拷贝一份传入函数时,将数组名 看做常量指针,传数组首元素的地址。

#include <stdio.h>
#include <stdlib.h>
/*------------------ <一维数组传参> -----------------------*/
/*方式一: 形参不指定数组大小
用数组的形式传递参数,不需要指定参数的大小,
因为在一维数组传参时,形参不会真实的创建数组,
传的只是数组首元素的地址。
*/

void method_1(int arr[], int len)
{
    for(int i=0; i<len; i++){
        printf(" arr[%d] = %d\n", i, arr[i]);
}
}

//方式二:指定数组大小
void method_2(int arr[10])
{
    for(int i=0; i<10; i++){
        printf(" arr[%d] = %d\n", i, arr[i]);
}
}
//方式三: 一维数组传参退化,用指针进行接收,传的是数组首元素的地址
void method_3(int *arr, int len)
{
    for(int i=0; i<len; i++){
        printf(" arr[%d] = %d\n", i, arr[i]);
}
}

int main102()
{
    int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    method_1(arr, 10);
    printf("------华丽的分隔线------\n");
    method_2(arr);
    printf("------华丽的分隔线------\n");
    method_3(arr, 10);

    system("pause");
    return 0;
}
/*-------------------- <指针数组传参> -----------------------*/
//方式一: 指针数组传参,声明成指针数组,不指定数组大小
void method_4(int *arr[], int len)
{
    for(int i=0; i<len; i++){
        printf(" arr[%d] = %d\n", i, *arr[i]);
}
}
//方式二: 指针数组传参,声明成指针数组,指定数组大小
void method_5(int *arr[10])
{
    for(int i=0; i<10; i++){
        printf(" arr[%d] = %d\n", i, *arr[i]);
}
}
//方式三: 二维指针传参
//传过去是指针数组的数组名,代表首元素地址,而数组的首元素又是一个指针,
//就表示二级指针,用二级指针接收
void method_6(int **arr, int len)
{
    for(int i=0; i<len; i++){
        printf(" arr[%d] = %d\n", i, *(*(arr+i)));
}
}
int main()
{
    int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int *arr_p[10] = {0};
    for(int i=0; i<10; i++){
        arr_p[i] = &arr[i];
}

method_4(arr_p, 10);
printf("------华丽的分隔线------\n");
method_5(arr_p);
printf("------华丽的分隔线------\n");
method_6(arr_p, 10);

system("pause");
return 0;
}

void 类型指针

void => 空类型 void* => 空类型指针,只存储地址的值,丢失类型,无法访问,要访问其值,我们必须对这个指 针做出正确的类型转换,然后再间接引用指针。

所有其它类型的指针都可以隐式自动转换成 void 类型指针,反之需要强制转换

#include <stdio.h>
#include <stdlib.h>
int main(void){
    int arr[]={1, 2, 3, 4, 5};
    char ch = 'a';
    void *p = arr;//定义了一个void 类型的指针
    //p++; //不可以, void * 指针不允许进行算术运算
    p = &ch; //其它类型可以自动转换成void * 指针
    //printf("数组第一个元素: %d\n", *p); //不可以进行访问
    printf("p: 0x%p ch: 0x%p\n", p, &ch);
    //强制类型转化

    char * p1 = (char *)p;
    printf("p1 指向的字符是: %c\n", *p1);

    system("pause");
    return 0;
}

函数指针

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int compare_int(const void *a, const void *b){
    //printf("调用compare_int 啦,你好骚气哦! \n");
    int *a1 = (int *) a;
    int *b1 = (int *) b;

    //printf("a 的地址: 0x%p b的地址: 0x%p\n", &a, &b);
    return *b1 - *a1;
}

int compare_char(const void *a, const void *b){
    //printf("调用compare_char 啦,你好骚气哦! \n");
    char c1 = *((char *) a);
    char c2 = *((char *) b);

    if(c1>='A' && c1<='Z') c1+=32;
    if(c2>='A' && c2<='Z') c1+=32;

    return c1 - c2;
}
int main(void){
    int x = 10;
    int y = 20;
    //函数有没有地址?
    //printf("compare_int 的地址: 0x%p \n", &compare_int);
    //compare_int(&x, &y);

    //函数指针的定义 把函数声明移过来,把函数名改成 (* 函数指针名)
    int (*fp)(const void *, const void *);
    /*贝尔实验室的C和UNIX的开发者采用第1种形式,而伯克利的UNIX推广者却采用第2
    种形式ANSI C 兼容了两种方式*/
    fp = &compare_int; //

    (*fp)(&x, &y); //第1种,按普通指针解引的放式进行调用,(*fp) 等同于compare_int

    fp(&x, &y); //第2种 直接调用

    //qsort 对整形数组排序
    int arr[]={2, 10, 30, 1, 11, 8, 7, 111, 520};

    qsort(arr, sizeof(arr)/sizeof(int), sizeof(int), &compare_int);

    for(int i=0; i<sizeof(arr)/sizeof(int); i++){
        printf(" %d", arr[i]);
    }

    //qsort 可以对任何类型的数组进行排序
    char arr1[]={"abcdefghiABCDEFGHI"};

    qsort(arr1, sizeof(arr1)/sizeof(char)-1, sizeof(char), &compare_char);

    for(int i=0; i<sizeof(arr1)/sizeof(char)-1; i++){
        printf(" %c", arr1[i]);
    }

    system("pause");
    return 0;
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:06:35  更:2022-11-05 00:07:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 17:18:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码