指针内容整理

指针

1、概念

把地址作为数据处理
指针变量:存储地址的变量
eg:a是变量b的指针,意思是a存了b的地址,也可以说a指向b.

2、指针变量的定义

类型标识符 *指针变量;

	int  *intp; //用*特别强调!!指针存的是起始地址!
	double *doublep;//这里加类型,是说明指针指向的单元的数据类型,输出的时候就只取那么多
	int *p, x, *q;//定义了俩指针和一个int变量,*必须每次都跟着

3、指针变量的赋值

  • 地址运算符 “&”表示取地址 p = &x;
    注意:& 运算符后面不能跟常量或表达式,如 &2 和 &(m * n + p )是没有意义的.
  • 改变指针的指向:通过对intp重新赋值intp=&y.
  • 同类的指针变量之间可相互赋值,表示两个指针指向同一内存空间。
  • 空指针:指针没有指向任何空间,用常量NULL表示,NULL的值一般赋为0
    注意:不能引用空指针指向的值(一般作为循环判断条件)

4、用指针变量对原单元的值进行操作

引用运算符 * 表示的是指针指向的这个单元的内容:*intp = 5 是把 x (intp指向的单元内容)改成 5.
注意:在对 intp 使用引用运算之前,必须先对 intp 赋值

5、注意事项

指针在使用前必须初始化。
空指针NULL是一个特殊指针值,它的值为0。它可被用来初始化一个指针,表示不指向任何地址。//空指针为假,其他为真

6、指针运算与数组

数组元素是一个独立的变量,因此可以有指针指向它:p = &a[1], p = &a[i]
数组名可以看成是常量指针,意思是不可以对数组名的变量进行操作.
如执行了p=array,则p与array是等价的,对该指针可以进行任何有关数组下标的操作
若定义 int a[10], *p,并且执行了 p = a,那么可用下列语句访问数组a的元素

for  ( i=0; i<10; ++i )
        cout <<  p[i]; //好怪救命

虽然通过指针可以访问数组,但两者本质是不同的:在定义数组时为数组的各个元素分配了全部的存储区,而在定义指针时仅仅分配四个字节的存储区存放指针地址。只有把一个数组名赋给了对应的指针后,指针才能当作数组使用.

7、指针运算

指针+1表示数组中指针指向元素的下一元素地址;
指针-1表示数组中指针指向元素的上一元素地址;
合法的指针操作:p + kp - kp1 - p2//p1和p2之间有几个元素
对数组:第i个元素的地址可表示为 intp + i,第i个元素的值可表示为 *(intp + i)等价于p[i]等价于a[i]

8、指针作为函数参数

用指针作为参数可以在函数中修改主调程序的变量值,即实现变量传递。必须小心使用!!!

void swap(int  *a, int *b){//*定义指针
	int c;
	c=*a;   *a= *b;     *b=c;//*对地址对应的单元操作
 } 
//用函数的时候:
swap(&x, &y)//&取地址

swap用引用更好

数组传递的本质是地址传递,因此形参和实参可以使用数组名,也可以使用指针。
数组传递时函数的声明可写为:

type fun(type a[], int size);

也可写为:

type fun(type *p, int size);

但在函数内部,a和p都能当作数组使用;调用时,对这两种形式都可用数组名或指针作为实参。调用举例:

fun(a,10);

建议:如果传递的是数组,用第一种形式;如果传递的是普通的指针,用第二种形式.

实例:分治法代码没写过,复制的老师的

void minmax ( int a[] , int n , int *min_ptr , int *max_ptr){
	 int  min1 , max1 , min2 , max2;
     switch(n){
     	    case 1: *min_ptr = *max_ptr = a[0]; return;
            case 2:  if (a[0] < a[1] ) {  *min_ptr = a[0];  *max_ptr= a[1];  }
                    else {   *min_ptr = a[1];  *max_ptr= a[0];}
                          return;//???????
            default: minmax( a, n/2, &min1, &max1 );
                          minmax( a + n/2, n - n / 2, &min2, &max2 );  
                          if (min1 < min2)
                              *min_ptr = min1;
                          else *min_ptr = min2;
                          if (max1 < max2)
                              *max_ptr = max2;
                          else *max_ptr = max1;
                         return;
	 }
}

9、返回指针的函数

类型 *函数名(形式参数表);

  • 当函数的返回值是指针时,返回地址对应的变量不能是被调函数的局部变量。
    理解:type a; type *b=&a;//指向type类型的指针

10、引用传递

减少星号的地址传递方式!
引用的定义:给一个变量取一个别名,但事实上指向同一个内存单元。
例子:

int i;
int &j=i; //&不要和取地址混淆了……救命
  • 引用实际上是一种隐式指针。每次使用引用变量时,可以不用书写间接引用运算符“*”,因而引用简化了程序。

  • C++引入引用的主要目的是将引用作为函数的参数。

  • 注意:
    定义引用时必须立即对它初始化,不能定义完成后再赋值;
    为引用提供的初始值可以是一个变量或另一个引用;
    引用不可重新赋值,不可使其作为另一变量的别名。//不能再改变了

  • sizeof(引用)得到的是该变量的大小;sizeof(指针)得到的是指针本身的大小(在32位系统中为4字节)。

  • 指针和引用的自增运算意义不一样。//指针+1是加上数据类型大小,引用是本身加1
    指针与引用的不同写法
    在这里插入图片描述理解:调用swap(x,y)时,相当于发生了变量定义 int &m = x; int &n = y,即形式参数m和实际参数x共享一块空间,形式参数n和实际参数y共享一块空间。在swap函数中交换了m和n的值,就相当于交换了x和y的值。意思就是,如果你想要在函数里面改变这个变量,引用传递更好使。

  • 如果在函数内不许改变参数的值,则参数用const限定。

  • 对非const的参数,实际参数不能是常量或临时量。

  • Const参数可以是常量

  • 关于函数模板的使用:什么时候复习函数模板?嗯?

template <int n>                     //n是一个非类型参数
void g(int (&arr)[n]){
	cout <<typeid(arr).name()<<"  "<< sizeof(arr) << endl; 
}

int main(){ 
	int a[10]={1,2,3,4,5,6,7,8,9,0};
	cout <<typeid(a).name()<<"  "<< sizeof(a) << endl;
	g(a);
	return 0;  
}
//输出:
//A10_i   40
//A10_i   40

勿混淆“”的两种不同用法:ab乘法,int a指针,后面再出现a表示引用,取值

例题

14291. 【原4291】凑数题

听说同学们学了指针,憨憨助教想借此机会考考大家,然而CPU大作业要写不完了,于是就有了这样一道凑数题…

写出以下代码中的两个函数funA和funB的声明与定义,使得funA(p)=a能实现通过指针p访问用户输入的字符串a,funB能将该字符串中的小写字母全部变成大写,并返回这个大写的字符串。

要求如下:
除了实现funA和funB外,不能修改包括main函数在内的其他代码,不能在全局定义新的变量、指针、数组和函数等,不能调用其他的库。
funA和funB内不能调用任何输入输出函数(包含但不限于cin,cout,scanf,prinf,getchar,putchar等等)。
不允许存在内存泄漏,由于OJ不能检测内存泄漏(同学们可以自行了解内存泄漏检测工具valgrind),助教将进行手动评测(以最后一次提交为准)。
用户输入的单个字符串长度不会超过98,而且只含有小写和大写字母。

#include <iostream>
#include <cstring>
using namespace std;

// 写出两个函数的声明

int main() {
    char a[100], b[100];
    for(int i = 0; i < 3; ++i) {
        char **p;
        cin >> a;
        funA(p) = a;
        cout << funB(b, p);
    }
    return 0;
}

// 写出两个函数的定义

Ans:

#include <iostream>
#include <cstring>
using namespace std;

char *&funA(char **&p);//char *表类型,&取地址,funA(char **表类型,&表引用)
char *funB(char targ[],char **p);

int main() {
    char a[100], b[100];
    for(int i = 0; i < 3; ++i) {
        char **p;
        cin >> a;
        funA(p) = a;
        cout << funB(b, p);
    }
    return 0;
}

char * &funA(char ** &p){
	p = new char *;//p指向存了char a位置的地址 
	return *p;//这个p现在和a一样了 
}

char *funB(char *targ,char **p){
	int len = strlen(*p);
	for(int i=1;i<=len;i++){
		if((*p)[i-1]>='a'&& (*p)[i-1]<='z') targ[i-1] = (*p)[i-1]+'A'-'a'; //注意(*p)是整体表示p指向的单元,是一个地址,然后再方括号[i-1]是取该地址的值
		else targ[i-1] = (*p)[i-1];
	}
	targ[len] = '\n';//记得换行
	targ[len+1] = '\0';
	return targ;
}

暂时还没有学习valgrind,学了来补充内容

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值