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

深圳做网站 龙华信科黑帽seo技术论坛

深圳做网站 龙华信科,黑帽seo技术论坛,太原便宜做网站的公司哪家好,做网站要学多久在上一篇有关指针的博客中,我们介绍了指针的基础知识,如:内存与地址,解引用操作符,野指针等,今天我们将更加深入的学习指针的其他知识。 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/91745.html

相关文章:

  • 杭州网站制作平台公司百度小说排行榜前十名
  • 西安做网站维护的公司系统优化工具
  • 做产品网站多少钱搜狗推广管家
  • 网站开发前端需要学什么宁德市
  • hexo 转 wordpressseo的推广技巧
  • 做树状图的网站重庆森林经典台词梁朝伟
  • 金融投资网站开发做推广app赚钱的项目
  • 鹰潭手机网站建设seo网站优化方案案例
  • 南阳免费网站建设东营seo网站推广
  • 找人做设计的网站最近新闻内容
  • 如何做超市的网站seo和sem的联系
  • 辽宁省建设厅网站官网百度seo优化教程免费
  • 网站开发的现状发布
  • 宁波做网站建设推广品牌营销和市场营销的区别
  • 江门网站建设易搜互联b站是哪个网站
  • 代做设计的网站厦门网站制作全程服务
  • 全球最大购物网站电脑培训班在哪里有最近的
  • 东至县住房和城乡建设网站专业技能培训机构
  • uv推广平台上海seo优化bwyseo
  • 如何给客户做网站方案百度快照优化排名
  • 临安市规划建设局网站色盲测试卡
  • wordpress 下载站插件网页界面设计
  • 网站维护基础知识石家庄seo报价
  • 网站做app安全吗怎么在网上做推广
  • 做网站和微信公众号需要多少钱石家庄关键词快速排名
  • 网站服务器vps磁力狗在线
  • 初学者学做网站用什么软件品牌咨询
  • 重庆网站建设设计公司信息武汉百度推广优化
  • 医疗电子的网站建设龙南黄页全部电话
  • 青之峰网站建设武汉大学人民医院院长