自学笔记

指针

1.指向数组元素的指针:

定义与赋值:例
int a[10],pa;
pa=&a[0];或者pa=a;
pa=a[0] ; (pa+1)=a[1];(pa+n)=a[n];
等效的形式: a[i],pa[i],
(pa+i),
(a+i);

a已经是首地址,&a没有意义。*pa为一个值,pa是一个地址指针。

2.指针数组:数组的元素是指针类型

例如:point *pa[2];这个就是由pa[0],pa[1]两个指针组成。
如下,可以采用指针数组的方式实现二维数组:

// 指针数组实现二维数组
#include<iostream>
int line1[]={1,0,0};
int line2[]={0,1,0};
int line3[]={0,0,1};
int main()
{
	int *pa[]={line1,line2,line3},i,j;
	std::cout<<"result:"<<std::endl; 
	for(i=0;i<3;i++){
    	for(j=0;j<3;j++)
	        std::cout<<pa[i][j]<<" ";
	     	std::cout<<std::endl; 
	}
	return 0;
}

二维数据和指针数组的区别:
二维数组:数组内的所有元素按行依次连续存放。
指针数组:多个指针所指向的数组不一定是依次连续存放的。
在这里插入图片描述

3.指针作为函数参数

为什么需要指针作为参数呢?
1、数据有时需要双向传递(引用也可以达到此效果)
2、若需要传递一组数据,只传首地址效率比较高

#include<iostream>
void splitFloat(float a,int *n,float *f){
	*n = a/1;
	*f = a-*n;
}
int main()
{
	float x,f;
	int n;
	std::cout<<"请输入三个浮点数:"<<std::endl;
	for(int i=0;i<3;i++){
		std::cin>>x;
		splitFloat(x,&n,&f);
		std::cout<<"整数部分为:"<<n<<"小数部分为:"<<f<<std::endl; 
	}
	return 0;
}
//将实参的地址赋给形参,调用函数操作形参就相当于直接操作了实参
//定义多个数,将其中需要返回的多个数进行取地址,然后调用函数直接对这取地址的多个数进行操作。 

如上实现了数据的双向传递。

若是只需要使用指针地址,不需要对其地址内的数据进行修改时,由于最小授权原则,最好使用常指针,即采用const定义指针

#include<iostream>
int printf(const int array[],int n);
int main(){
	int n=2;
	int array[n];
	std::cout<<"请输入两个数组元素:" <<std::endl; 
	for(int i=0;i<n;i++)
		std::cin>>array[i];
		printf(array,n);
	return 0;
}
int printf(const int *p,int n){
	std::cout<<"{"<<*p<<" ";
	for(int i=1;i<n;i++)
	 std::cout<<p[i] <<std::endl; 
	 std::cout<<"}";
}

4.指针类型的函数

不要将非静态局部地址作为函数的返回值,返回的指针要确保在主调函数中是合法有效的地址。
错误的例子:在子函数中定义局部变量后将其地址返回给主函数,该地址为非法地址。

#include<iostream>
int *function();
int main(){
	int *p=funtion();
	*p=2;
	return 0; 
} 
int *function(){
	int local=0;
	return &local;
}//函数运行结束时,变量local被释放 ,主函数接收到一个非法地址 ,在*p=2这个赋值中是个危险的访问 

正确例子1:主函数中定义数组,在子函数中对该数组元素进行操作后返回其地址,这是合法的

#include<iostream> 
int *find(int *a,int num); 
int main(){
	int array[10];
	for(int i=0;i<10;i++)
		std::cin>>array[i];
		int *ad =find(array,10);
		return 0;
}
int *find(int *a,int num){
	for(int i=0;i<10;i++)
	if(a[i]==1)
		return &a[i];
}

正确例子2:在子函数中通过动态分配new操作取得的内存地址返回给主函数时合法有效的(但是内存分配和释放不在同一级别,要注意不能忘记释放,避免内存泄漏)

#include<iostream>
int *function();
int main(){
	int *p=function();
	*p=2;
	delete p;//如果忘记释放,则会造成内存泄漏 
	return 0;
}
int *function(){
	int *l=new int();//动态分配一个地址,在函数运行结束时,内存不会被释放,即返回地址有效 
	return l;
}

5.函数指针

函数指针指向程序代码存储区的首地址。
典型用处:实现函数回调,通过函数指针调用函数(存在一个通用函数,比如“计算”,再通过这个通用函数的不同形参去调用其他具体函数,比如“加减乘除”)

#include<iostream>
int computer(int a,int b,int (*function)(int,int)) {
	return function(a,b);
}
int max(int a,int b){
	return ((a>b?a:b));
}
int min(int a,int b){
	return((a<b?a:b));
}
int sum(int a,int b){
	return a+b;	
}
int main(){
	int a,b,c;
	std::cout<<"请输入a:";std::cin>>a;
	std::cout<<"请输入b:";std::cin>>b;
	c=computer(a,b,&max);
	std::cout<<"max of a and b is"<<c<<std::endl; 
	c=computer(a,b,&min);
	std::cout<<"min of a and b is"<<c<<std::endl; 
	c=computer(a,b,&sum);
	std::cout<<"sum of a and b is"<<c<<std::endl; 
	 
}

每日一题

实现 int sqrt(int x) 函数。
计算并返回 x 的平方根,其中 x 是非负整数。
由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去。
示例 1:
输入: 4
输出: 2

示例 2:
输入: 8
输出: 2
说明: 8 的平方根是 2.82842…,
由于返回类型是整数,小数部分将被舍去。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sqrtx

解:由于 x 平方根的整数部分n是满足 k^2<≤x 的最大 k值,因此我们可以对 k 进行二分查找,从而得到答案。
二分查找的下界为 0,上界可以粗略地设定为 x。在二分查找的每一步中,我们只需要比较中间元素mid 的平方与 x 的大小关系,并通过比较的结果调整上下界的范围。由于我们所有的运算都是整数运算,不会存在误差,因此在得到最终的答案n后,也就不需要再去尝试 n+1 了。

class Solution {
public:
    int mySqrt(int x) {
        int l = 0, r = x, ans = -1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if ((long long)mid * mid <= x) {
                ans = mid;
                l = mid + 1;
            }
            else {
                r = mid - 1;
            }
        }
        return ans;
    }
};

今日收获小知识

1.不要在程序中去比较两个浮点数的大小,即使明明应该相等结果也有可能出现不等,因为浮点数的存储时近似存储的。若一定要比较,则可以将两个数做差,出来的数小于达到一定范围,比如小于10的负很多次方则认为这两个数相等。
2.C里面是没有专门的整除符号的,有的只有除号“/"。
当除数和被除数都是整型时就是整除。例如:
int a=3,b=2;int c=a/b;
此时就是计算的整除,3/2返回的值是1
如果想普通除法得到1.5,应该写成3.0/2。
3.std 是一个c++中的标准命名空间。std是一个用C写出来的一个特殊的类,或者说接口,里面装着C++(认为是C的扩展包,其实大误)各种各样的函数名。using namespace std;就是相当于导入std这个包。但是由于C++的特殊机制,相当于在程序中定义了一系列的全局变量。这些全局变量直接一次性的全部都被定义出来了。但是,当你再去定义自己的函数的时候,你根本就不知道自己定义的函数名是否和std标准命名空间里的函数名重名。所以,并不推荐直接使用using namespace std;
那么怎么用呢?
或许你可以试一下仅把自己需要用到的函数名导入一下。
C++ std中常用的函数就是那么几个,随用随导就可以了。
#include
using namespace std::cin;//使用(导入)C++中的输入流
using namespace std::cout;//使用(导入)C++中的输出流
using namespace std::endl;//使用(导入)输出换行符
原文链接:https://blog.csdn.net/Amber_technology/article/details/104887819

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值