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

游戏科技优化搜索引擎

游戏科技,优化搜索引擎,武汉市注册公司流程和费用,网页制作与网站建设试卷在上一篇有关指针的博客中,我们介绍了指针的基础知识,如:内存与地址,解引用操作符,野指针等,今天我们将更加深入的学习指针的其他知识。 1.指针的使用和传址调用 1.1strlen的模拟实现 库函数strlen的功能是…

在上一篇有关指针的博客中,我们介绍了指针的基础知识,如:内存与地址,解引用操作符,野指针等,今天我们将更加深入的学习指针的其他知识。

1.指针的使用和传址调用

1.1strlen的模拟实现

库函数strlen的功能是求字符串长度,统计的是字符串中\0之前的字符个数

 函数原型如下:

size_t strlen (const char* str);

 参数str接收一个字符串的起始地址,然后开始统计字符串中\0之前的字符个数,最终返回长度。关于strlen函数的详细介绍网页:
strlen - C++ Referencehttps://legacy.cplusplus.com/reference/cstring/strlen/?kw=strlen我们要实现该函数的模拟实现,就要从字符串起始地址开始逐个遍历字符,只要不是\0字符,计数器就加一, 直到\0结束。

#include<stdio.h>
#include<assert.h>int my_strlen(char* str)
{assert(str != NULL);char* pz = str;while (*pz != '\0'){pz++;}return pz - str;
}int main()
{int len = my_strlen("abcdef");printf("%d\n", len);return 0;
}

 在代码里,我们用到了assert断言,他帮助我们判断str是否为空指针,如果是,程序会报错。


1.2传值调用和传址调用

学习指针的目的是使⽤指针解决问题,那什么问题,非指针不可呢?
例:写一个函数,交换两个整型变量的值
我们可能会写出这样的代码:
 
void Swap(int x, int y)
{int temp = x;x = y;y = temp;
}int main()
{int num1 = 10;int num2 = 20;printf("交换前:num1 = %d,num2 = %d\n", num1, num2);Swap(num1, num2);printf("交换后:num1 = %d,num2 = %d\n", num1, num2);return 0;
}

 代码运行结果:
 

我们发现没有产生预期的效果,为什么呢?调试观察一下:

 

我们发现在main函数内部,创建了num1和num2,num1的地址是0x0019f7e8,num2的地址是0x00197fdc,在调用Swap函数时,将num1和num2传递给了Swap函数,在Swap函数内部创建了形参x和y接收num1和num2的值,但是x的地址是0x0019f704,y的地址是0x0019f708,x和y确实接收到了num1和num2的值,不过x的地址和num1的地址不⼀样,y的地址和num2的地址不⼀样,相当于x和y是独⽴的空间,那么在Swap函数内部交换x和y的值,⾃然不会影响num1和num2,当Swap函数调⽤结束后回到main函数,num1和num2的没法交换。Swap1函数在使用的时候,是把变量本身直接传递给了函数,这种调用函数的⽅式我们之前在函数的时候就知道了,这种叫传值调用。
实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实
参。

 所以上述代码实际是不符合题目要求的。

该怎样设计代码呢,既然我们把交换数值传到函数内无法实现交换,那如果传输的是地址呢,同一份内存空间还会不会失败?

void Swap(int* px, int* py)
{int* temp = px;*px = *py;*py = *temp;
}int main()
{int num1 = 10;int num2 = 20;printf("交换前:num1 = %d,num2 = %d\n", num1, num2);Swap(&num1, &num2);printf("交换后:num1 = %d,num2 = %d\n", num1, num2);return 0;
}

查看结果,我们发现交换成功了。

 调用Swap函数的时候是将变量的地址传递给了函数,这种函数调用方法叫:传址调用。

传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用。如果函数内部要修改主调函数中的变量的值,就需要传址调用。

 2.数组名的理解

在上篇博客我们在使用指针访问数组的内容时,有这样的代码:
 

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

 这里我们使用arr的方式拿到了数组第一个元素的地址,有些人可能会有疑惑?不应该&arr[0]才是数组第一个元素的地址吗,其实,大部分情况这两种写法是一样的意思,并没有含义的不同,我们来做一个测试。

我们发现数组名和数组首元素的地址打印出的结果一模一样 ,数组名就是数组首元素的地址

这时候可能有同学有疑问?数组名如果是数组首元素的地址,那下面的代码又该如何理解?

 我们看到上述代码的结果是40,如果arr是数组首元素的地址,其结果应该是4/8才对。

其实数组名就是数组首元素的地址是对的,但是有两个例外:

• sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
• &数组名,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)
除此之外,任何地方使用数组名,数组名都表示首元素的地址。

 这时有好奇的同学,尝试了如下代码:

三个打印结果一模一样,他就不会区分了,明明结果是一样,含义却不同吗?

我们再看下面这个代码:
 

我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1 也相差4个字节,是因为&arr[0] 和 arr 都是首元素的地址,+1就是跳过⼀个元素。
但是&arr 和 &arr+1相差40个字节,这就是因为&arr是整个数组的地址,+1 操作是跳过整个数组的。
到这里⼤家应该搞清楚数组名的意义了吧。
数组名是数组首元素的地址,但是有2个例外。

3.使用指针访问数组

有了前⾯知识的⽀持,再结合数组的特点,我们就可以很⽅便的使⽤指针访问数组了。
int main()
{int arr[10] = {0};int* p = arr;int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < sz; i++){scanf("%d", p + i);}for (int i = 0; i < sz; i++){printf("%d\n", *(p + i));printf("%d\n", p[i]);//这一行代码效果与上一行代码效果完全相等}return 0;
}

在该代码中,将*(p+i)换成p[i]也是能够正常打印的,所以本质上p[i] 是等价于 *(p+i)。


4.一维数组传参的本质

我们发现在函数内部无法正确获取数组的元素个数。这是为什么呢?

这时候就要学习数组传参的本质了 ,之前说过,数组名是数组首元素的地址,那么在数组传参的时候,传递的是数组名,本质上传递的其实是数组首元素地址,并不会传递整个数组,这两者是有区别的。

所以函数形参的部分理论上应该使用指针变量来接收首元素的地址。那么在函数内部我们写
sizeof(arr) 计算的是⼀个地址的大小(单位字节)而不是数组的大小(单位字节)。
void test(int arr[])
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}void test(int* p)
{int sz2 = sizeof(p) / sizeof(p[0]);printf("sz2 = %d\n", sz2);
}

这两者是等效的。

总结:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

 5.二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥? 答案是二级指针。

 如上图,a是整型变量,他的地址存放在pa中,pa的类型是int*,pa的地址又存放在ppa中,ppa的类型是int**,这就是二级指针。

对于二级指针的运算有:

int a = 20;
*ppa = &a;

 *ppa 通过对ppa中的地址进⾏解引用,这样找到的是 pa *ppa 其实访问的就是 pa。

**ppa = 30;
//等价于*pa = 30
//等价于a = 30

 **ppa 先通过 *ppa 找到 pa ,然后对 pa 进⾏解引⽤操作: *pa ,那找到的是 a 。

6.指针数组

6.1指针数组概念

指针数组是指针还是数组?
我们类比⼀下,整型数组,是存放整型的数组,字符数组是存放字符的数组。
那指针数组呢?是存放指针的数组。

 这是一个典型的指针数组,他的每一个元素都是地址,只想某一块区域。

6.2指针数组模拟二维数组

int main()
{int arr1[5] = { 1,2,3,4,5 };int arr2[5] = { 2,3,4,5,6 };int arr3[5] = { 3,4,5,6,7 };int* arr[3] = { arr1,arr2,arr3 };for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", arr[i][j]);//printf("%d ", *(*(arr+i)+j));//两行效果一致}printf("\n");}return 0;
}

arr[i]是访问arr数组中的元素,arr[i]找到的数组元素指向了一个一维整型数组,所以arr[i][j]就是一维整型数组的元素。

要注意,上述的代码虽然模拟出了二维数组的效果,实际上却不是真正的二维数组,因为每一行并非是连续的。
http://www.dtcms.com/wzjs/40274.html

相关文章:

  • 网站建设 石家庄游戏推广公司
  • 做专柜品牌特卖的网站域名注册要多少钱
  • 外汇跟单网站建设建立网站流程
  • 学校网站建设全包百度公司招聘
  • 哪个网站的理财频道做的比较好sem搜索引擎营销
  • 宝安附近做网站公司成都关键词seo推广电话
  • 皮具网站建设小视频网站哪个可以推广
  • 网站织梦后台怎么做今日国际新闻头条15条
  • 哪里可以鉴定钻石企业seo排名费用报价
  • 制作网站注册页面模板实时新闻最新消息
  • 做网站的费用怎么做账爱站工具包下载
  • 宁波高端网站设计价格网站运营培训学校
  • 你做网站群好朋友的作文百度正版下载恢复百度
  • 在IIs下建设一个网站武汉网站推广很 棒
  • 网络营销人员招聘高级seo招聘
  • 南宁定制网站建设谷歌play商店
  • 湖南做网站磐石网络案例软文广告属于什么营销
  • 铜陵高端网站建设怎么制作网页推广
  • 威海泰浩建设集团有限公司网站今日重要新闻
  • 什么服装网站做一件代发西安网站设计公司
  • 保险代理人做网站网络营销方式哪些
  • 青青网站怎么做百度应用app下载
  • 怎么做网站营销百度一下百度百科
  • 商城网站风格南宁百度推广排名优化
  • 手机怎么打开禁止访问的网站网络推广渠道排名
  • 做建筑设计的网站推荐美国疫情最新情况
  • 屏南网站建设兼职新网站友链
  • 网站建设和成本2023年的新闻十条
  • 怎样做网站测试百度天眼查公司
  • 重庆市建设政务中心网站2345手机浏览器