当前位置: 首页 > news >正文

河北交通建设投资集团公司网站/千峰培训可靠吗?

河北交通建设投资集团公司网站,千峰培训可靠吗?,建新建设集团有限公司网站,陕西精诚展览装饰有限公司文章目录指针进阶0.前言1. const修饰指针2. 字符指针2. 指针数组3. 数组指针1) 数组指针概念2) 数组名 和 &数组名3) 数组指针的使用4) 简单汇总4. 数组和指针传参1) 一维数组传参2) 二维数组传参3) 一级指针传参4) 二级指针传参指针进阶 0.前言 从上一篇博客指针入门我们…

文章目录

  • 指针进阶
    • 0.前言
    • 1. const修饰指针
    • 2. 字符指针
    • 2. 指针数组
    • 3. 数组指针
      • 1) 数组指针概念
      • 2) 数组名 和 &数组名
      • 3) 数组指针的使用
      • 4) 简单汇总
    • 4. 数组和指针传参
      • 1) 一维数组传参
      • 2) 二维数组传参
      • 3) 一级指针传参
      • 4) 二级指针传参


指针进阶

0.前言

从上一篇博客指针入门我们知道了,几点

  1. 指针是一个变量,存放的是地址,地址是某一块内存空间的唯一标识
  2. 指针的大小在不同平台的大小不一样,32位平台的是4个字节,64位平台是8个字节
  3. 指针的类型决定了指针解引用和指针加减能走多远

1. const修饰指针

我们知道const修饰一个变量,它就是一个常变量是不会被直接修改的。

#include <stdio.h>int main()
{const int num = 10;num = 10; //这里会报错return 0;
}

当我们可以通过指针来进行修改,也就是不直接对它进行修改,而是取出它的地址通过地址来对它进行修改。

#include <stdio.h>int main()
{const int num = 10;int* p = &num;*p = 20; //num被修改成了20printf("%d\n", num);return 0;
}

那么const的就失去了原本的意义,其实还有一种另外的方式可以达到我们想要的效果。那就是const修饰指针

代码示例:如果再尝试使用地址的方式修改变量编译器就会报错。

#include <stdio.h>int main()
{int num = 10;const int* p = &num;//int const* p = &num; 这两个写法没区别*p = 20;printf("%d\n", num);return 0;
}

那么问题又来了,我们不能通过地址修改但此时又可以通过直接修改的方式进行修改

#include <stdio.h>int main()
{int num = 10;const int* p = &num;num = 20;// num被修改成了20printf("%d\n", num);return 0;
}

依旧是可以解决的,我们在用一个const修饰一下 p就好了,再用const修饰变量,此时无论是直接修改还是通过取地址都无法修改num的值了,那const到底怎么修饰指针呢?

#include <stdio.h>int main()
{const int num = 10;//让num不能通过变量名修改const int* const p = &num;//不允许通过*修改num的地址,同时指针变量p也不能被改变printf("%d\n", num);return 0;
}

总结:

  • const写在星号*左边,修饰的是指针指向的内容,使得指针指向的内容,不能通过指针来改变。但是指针变量本身是可以修改的。

    #include <stdio.h>int main()
    {int num = 10;int n = 100;const int*  p = &num;*p = 20;//错误写法p = &n; //正确写法num = 200;//正确写法return 0;
    }
    
  • const写在星号*右边,修饰的是指针变量本身,使得指针变量本身不能修改。但是指针指向的内容可以通过指针来改变,是可以修改的。

    #include <stdio.h>int main()
    {int num = 10;int n = 100;int* const  p = &num;*p = 20;//正确写法p = &n; //错误写法num = 200; // 正确写法return 0;
    }
    

2. 字符指针

在C语言中字符指针用char*来表示

#include <stdio.h>int main()
{char c = 'Q';char* cp = &c;printf("%c\n", *p);return 0;
}

char*还有另外一种用途,那就是常量字符串

#include <stdio.h>int main()
{char* str = "hello";// 常量字符串char arr[] = "hello";printf("%c\n", *str);printf("%s\n", str);printf("%s\n", arr);return 0;
}

str 里存放的是“hello”字符串的首地址,且这是一个常量字符串,也就是它不能被修改

而arr是一个字符数组它是可以被修改的

在这里插入图片描述

再来看一段代码

#include <stdio.h>int main()
{char* str1 = "hello";char* str2 = "hello";char arr1[] = "hello";char arr2[] = "hello";if (str1 == str2){printf("str1 == str2\n");}else{printf("str1 != str2\n");}if (arr1 == arr2){printf("arr1 == arr2\n");}else{printf("arr1 != arr2\n");}return 0;
}

运行结果

str1 == str2
arr1 != arr2

str1 == str2 是因为,"hello"是一个常量字符串,常量字符串是不能被修改的。所以常量字符在内存中只会存一份,所以 str1和str2存放的都是 “hello”这个字符的首地址

而arr1 和 arr2 是数组名,数组名存储放的是首元素的地址,这是两个不同的数字当然不相等。

注意:比较字符串相等要使用 strcmp

在这里插入图片描述

2. 指针数组

整形数组、字符数组都是数组,那么指针数组也是数组,它是一个存放指针的数组。上一篇博客也提到过

基本语法

#include <stdio.h>int main()
{int* arr[10];//整形指针数组char* ch[10]; //字符指针数组int** arrP[10]; //二级整形指针数组int a = 10;char c = 'a';int* p = &a;arr[0] = &a;ch[0] = &c;arrP[0] = &p;printf("%d\n",*arr[0]);printf("%c\n",*ch[0]);printf("%d\n",**arrP[0]);//第一次解引用拿到一级指针p的地址,再次解引用就拿到了a的地址return 0;
}

3. 数组指针

1) 数组指针概念

数组指针是指针还是指针?

我们知道整形指针int *指向的是一个整形变量,也知道字符指针char*指向的是一个字符变量,那么数组指针它也是一个指针,它是一个指向数组的指针。

那么下面两个哪个才是数组指针呢?

int *arrP[10];
int (*pArr)[10];
  • int *arrP[10],因为[]的优先级要高于*,所以arrP会和[]先结合变成arrP[10]这就是一个数组,那么int就会和*结合变成int *,那么此时就变成了一个int*类型的数组,也就是整形指针数组
  • (*pArr)括起来,那么它们结合就是一个指针,指向了一个数组[10],所以这里可以描述为,*pArr指向了一个10个元素的数组,每个元素的类型是int,所以int (*pArr)[10]是一个数组指针

2) 数组名 和 &数组名

我们给一个数组

int arr[10]

这个数组的arr&arr分别是啥?

来看一段代码

#include <stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%p\n", arr);printf("%p\n", &arr);return 0;
}

打印结果:发现arr和&arr的地址是一样的?我们知道arr存的是数组首元素的地址,那 &arr也是吗?并不是

00000030B82FFCF8
00000030B82FFCF8

再来看一段代码

#include <stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%p\n", arr);printf("%p\n", &arr);printf("==========\n");printf("%p\n", arr+1);printf("%p\n", &arr+1);return 0;
}

打印结果

000000FA108FF608
000000FA108FF608
==========
000000FA108FF60C
000000FA108FF630

我们发现,arr&arr打印的地址是一样的。但是它们的意义是完全不一样的。

arr+1只是跳过了4个字节的地址,而&arr+1则是条过了40个字节的地址,相当于跳过了整个数组。

从这里看出来&arr取出的是整个数组的地址!

注意:

  • &数组名
  • sizeof(数组名)
  • 除此上面2种情况之外-所有遇到的数组名都是数组首元素的地址

3) 数组指针的使用

了解了数组指针,那么数组指针是怎么使用的呢?

整形指针存的是整形的地址,那么数组指针指向的是一个数组,那它存的就是数组的地址。

前面我们了解到通过指针±可以遍历数组,指针p存的是数组首元素的地址,那么怎么通过数组指针遍历数组呢?

#include <stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = arr;int i = 0;for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", *(p+i));}return 0;
}

数组指针的使用,通过使用数组指针,用三种不同的方式遍历整个数组(注意:一下写法一般不会使用)

#include <stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int(*pArr)[10] = &arr;int i = 0;for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", (*pArr)[i]);}printf("\n");for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", *(*pArr+i));}printf("\n");for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){printf("%d ", pArr[0][i]);//等价于//printf("%d ", *(*(p) + i))}return 0;
}
  • (*pArr)拿到的是整个数组的地址,而整个数组的地址是有arr来维护的,其实*pArr[0]等价于arr[0],也就可以理解为 *pArr <==> arr
  • 第二种写法:*pArr等价于arr,那么其实它就是首元素的地址,那么*pArr+i其实拿到的是下标为 i 元素的地址,再对其解引用拿到的就是这个元素
  • 第三种写法:pArr[0]其实等价于*(pArr+0),也就是说 pArr[0][i]<==> *(*(p+0) + i))

上面的那些写法让人决得很变扭,一般不会这么写。

来看看正常的数组指针的使用,一般是用于二维数组

我们通过函数来打印数组正常传参,传过去的是二维数组就通过二维数组来接收。其实还可以通过数组指针来接收。

#include <stdio.h>void prt1(int arr[3][4], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int j = 0;for (j = 0; j < col; j++){printf("%d ", arr[i][j]);}printf("\n");}}
void prt2(int (*p)[4], int row, int col)
{int i = 0;for (i = 0; i < row; i++){int  j = 0;for (j = 0; j < col; j++){printf("%d ", *(*(p + i) + j));}printf("\n");}
}
int main()
{int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };prt1(arr, 3, 4);prt2(arr, 3, 4);return 0;
}

数组名是首元素地址,而二维数组的数组名则是二维数组第一行的地址。

那么*(*(p+i)+j)是什么意思呢?

  • p 是第一行的地址
  • p+i 是跳过i行后的那一行的地址
  • *(p+i) 跳过i行之后的那一行,也就相当于这一行的数组名
  • (*(p+i)+j) 跳过i行后的那一行的下标为j的元素地址
  • *(*(p+i)+j) 跳过i行后的那一行的小标为j的元素

需要注意的是,这里传递过去的是数组数组名,也就是数组首元素的地址,也就是二维数组的第一行。

再来看一段代码

#include <stdio.h>int main()
{int arr[3][4] = { 0 };int (*p1)[4] = arr;//二维数组首元素,也就是第一行的地址int (*p2)[3][4] = &arr;//这是整个二维数组的地址printf("%p\n", p1);printf("%p\n", p2);printf("==============\n");printf("%p\n", p1+1);printf("%p\n", p2+1);return 0;
}

运行结果:我们发现p1+1只是跳过了一行一行4个元素也就是16个字节,而p2+1跳过了整个二维数组,也就是48个字节。说明二维数组其实和一维数组,数组名和&数组名是一样的。

0000002D8135F4B8
0000002D8135F4B8
==============
0000002D8135F4C8
0000002D8135F4E8

4) 简单汇总

//这是普通数组
int arr[10];
// pArr1和[]结合这是一个数组,int*结合,所以这一个 指针数组
int *pArr1[10];
// *和pArr2结合,这是一个指针,指向的是一个存放10个元素的数组,数组的类型是Int。所以这是一个指针数组
int (*pArr2)[10]; 
// pArr3和[]先结合这是一个数组,它是存放数组指针的数组
int (*pArr3[10])[5]; 

解释一下最后一个数组

pArr3和[]结合他是一个数组,每个数组有10个元素

把数组名去掉,剩下的就是元素类型 int (*)[5],这是一个指针指向一个元素5个元素的数组,每个数组的元素类型是int

比如 int (*p)[5] = &arr; 这是一个数组指针,假设把p去掉 int(*)[5],剩下的就是它的元素类型了。

pArr3[10]是一个存放数组指针的数组,数组有10个元素

所以这是一个

int main()
{int arr1[5] = { 0 };int arr2[5] = { 0 };int arr3[5] = { 0 };int (*pArr3[10])[5] = { &arr1,&arr2,&arr3 };return 0;
}

在这里插入图片描述

4. 数组和指针传参

1) 一维数组传参

#include <stdio.h>
//数组传参数组接收没问题
void test1(int arr[]){}
//数组传参数组接收写了元素类型也没问题(这本质是一个指针,写不写都一样)
void test1(int arr[10]){}
//传数组名,本质上就是首元素的地址,没问题
void test1(int* arr){}
//传指针数组,指针数组接收每问题
void test2(int* arr[20]){}
//指针数组的数组名本质上也是一个地址,数组的每个元素都是int* 类型,那它的首元素就是一个一级指针,用一个二级指针接收一级指针每有任何问题
void test2(int** arr){}
int main()
{int arr[10] = { 0 };int* arr2[20] = { 0 };test1(arr);test2(arr2);
}

2) 二维数组传参

#include <stdio.h>
//传二维数组用二维数组接收每任何问题
void test(int arr[3][5]){}
//在C语言中二维数组的列是不能省略的!
void test(int arr[][]){}
//省略行每任何问题,省略行没问题,可以不知道有多少行,但必须知道每行有多少列,猜方便运算
void test(int arr[][5]){}
//二维数组传的是二维数组首元素也就是第一行的地址,拿一个int* 的指针来接收肯定是不行的。可以存放到数组指针去
void test(int* arr){}
//这是明显错误的,这么写表示这是个整形指针数组
void test(int* arr[5]){}
//这是正确的写法,这是一个指针指向了一个二维数组第一行的地址,数组每一个行有5个元素,
void test(int(*arr)[5]){}
//错误写法,这是一个二级指针,只能用来接收一个一级指针的地址
void test(int** arr){}
int main()
{int arr[3][5] = { 0 };test(arr)}

3) 一级指针传参

一个int*的指针能接收什么参数?

#include <stdio.h>
void test(int *p)
{}int main()
{int a = 10;int *pa = &a;int arr[10] = {0};//下面三中写法都是正确的test(&a);test(pa);test(arr);return 0;
}

char*又能接受什么参数?

char*有两种表示形式,一种是字符指针,一种是字符串,存的是字符串的收地址。

#include <stdio.h>
void test(char *p)
{}int main()
{char c = 'a';char str[] = "hello";char arr[] = {'h','e','l','l','o','\0'};test(&c);test(str);test(arr);return 0;
}

4) 二级指针传参

二级指针存放的是一级指针的地址,所以传递个一级指针的地址,或者二级指针都是可以的

#include <stdio.h>
void test(int** p)
{printf("%d\n", **p);
}int main()
{int a = 10;int* p = &a;int** pp = &p;test(&p);test(pp);return 0;
}

http://www.lbrq.cn/news/826669.html

相关文章:

  • 太原网页设计师/seo技术学院
  • 企业自助建站软件/免费的api接口网站
  • 公司网站建设完成通知/seo优化按天扣费
  • 宜兴做网站的联系方式/市场seo是什么
  • 内容电商的网站如何做/发稿服务
  • 哈尔滨网站制作公司/seo免费诊断联系方式
  • 网站建设服务领域/公司网站优化
  • 怎么用新浪云做网站/网站优化排名软件网
  • 专业网站制作公司/商丘搜索引擎优化
  • 网站运营计划书/企业培训机构有哪些
  • 利为汇网站建设/国内最新消息新闻
  • 摄影网站建立/网络营销公司怎么注册
  • 金融网站可以做公安备案/推广关键词
  • 会展网站建设情况/html网页制作代码大全
  • linux系统网站建设/百度搜索热度指数
  • o2o网站建设如何/快速搭建网站的工具
  • 简单的网站/免费网站建设哪家好
  • 交通设施东莞网站建设/网络营销方案案例
  • 部门做网站优点/淘宝网店的seo主要是什么
  • 有做公司网站/上海快速排名优化
  • 深度开发/网店seo关键词
  • 老网站不要了做新站需要怎么处理/网络舆情管控
  • 常州网站开发公司/上海网络推广公司网站
  • 重庆网站开发公/网络游戏营销策略
  • 做网站要会写代码吗/济南做网站公司哪家好
  • 成都企业建站系统/今天新闻头条最新消息
  • 建站系统破解/网络推广怎么做?
  • 国内做博彩网站代理/石家庄seo结算
  • 洛阳网红打卡地/seo详细教程
  • 南京做网站/高级seo培训
  • 零基础学习性能测试第三章:执行性能测试
  • 黑马教程Webday6
  • 【理财】为什么要进行资金预留
  • MyBatis动态SQL全解析:五大核心标签实战指南
  • OpenCV 官翻7 - 对象检测
  • 注册表单案例