C语言中没有引用,只有取地址&
C++语言中有引用&,也有取地址&
(引用就是给变量起别名,对别名的操作就是对原变量的操作)

首先要明白的两点:

  1. 对顺序表的取值、查找操作不需要对顺序表进行修改
  2. 对顺序表的初始化、插入、删除操作需要对顺序表进行修改

原结构体

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 20          /* 存储空间初始分配量 */
typedef int ElemType;       /* ElemType类型根据实际情况而定,这里假设为int */
typedef struct
{
    ElemType data[MAXSIZE]; /* 数组存放顺序表的数据元素 */
    int length;             /* 顺序表的当前长度 */
}SqList;

1.某被调函数不需要对原结构体中的 data 和 length 进行修改时,形参就使用

SqList L	//某被调函数不需要修改原结构体,使用原结构体当中的数据

2.某函数需要对原结构体中的 data 和 length 进行修改时,形参就使用

SqList *L 	//某被调函数中的操作要修改原结构体中数据(也可以使用原结构体数据)
//C++中使用引用&
SqList &L	//这里的L为结构体的别名,被调函数中对结构体的操作就是对原结构体的操作

上述两个形参的类型定义相当于拥有了将改变后的数据进行”回传“的功能
(在函数结束后销毁变量的情况下,将改变后的数据保留了下来)
是否需要 “回传” 重点在于主调函数后面的语句中是否需要这个改变了的新数据

个人理解(可能有误)
至于为何它们有类似"回传"的功能,也就是在函数结束销毁变量后,仍会保留下新数据的功能?

  1. 因为主调函数将实参的存储地址传给此形参(指针变量*L),而被调函数中的操作是对其存储内容进行改变,其存储地址没有发生变化,所以无论该存储内容如何变化,最终都会根据该变量的存储地址找到最新的存储内容。(In a word,通过存储地址"跟踪"存储内容)
  2. 引用其实是给变量起的别名,对别名的操作就是对原变量的操作

1.某函数不需要原结构体进行修改时,形参就使用

SqList L

对顺序表的取值操作

#define MAXSIZE 20          
typedef int ElemType;      
typedef struct
{
    ElemType data[MAXSIZE]; 
    int length;             
}SqList;
//被调函数
Status GetElem(SqList L,int i,ElemType *e){	
//此函数没有对L中的data或length作出改动,使用普通类型L,无需"回传"给主调函数变化后值,因为没有改变
//此函数对e作出了改动,需要"回传"给主调函数,所以使用指针类型*e
    if(L.length==0 || i<1 || i>L.length)
            return ERROR;
    //对e进行了改动(初始化了e)
    //解引用 e 以存储数据
    *e=L.data[i-1];

    return OK;
}
//主调函数
int main(){
	...
	SqList L;
	ElemType e;
	GetElem(L,5,&e);	//&e将变量e的存储地址传给被调函数的指针变量*e来保存,从而获取到被调函数改动后的e的值
	printf("第5个元素的值为:%d\n",e);	//这里e为改动后的值("回传"的新e)
	...
	return 0;
}

对顺序表的查找操作

typedef struct
{
    ElemType data[MAXSIZE]; /* 数组,存储数据元素 */
    int length;             /* 线性表当前长度 */
}SqList;

int LocateElem(SqList L,ElemType e){
//该被调函数并未对L、e作出改动,无需"回传",所以使用普通类型
    int i;
    if (L.length==0)
            return 0;
    for(i=0;i<L.length;i++)
    {
            if (L.data[i]==e)
                    break;
    }
    if(i>=L.length)
            return 0;

    return i+1;
}

int main(){
	SqList L;
	int j,k;
	....
	for(j=3;j<=4;j++)
    {
            k=LocateElem(L,j);	//此函数返回的是i+1
            if(k)
                    printf("第%d个元素的值为%d\n",k,j);
            else
                    printf("没有值为%d的元素\n",j);
    }
    ....
    return 0;
}

2.某函数需要对表内数据元素进行修改时,形参就使用

SqList *L 	//可以修改原结构体当中的数据
SqList &L	//C++中使用&
//被调函数中形参&L是主调函数实参变量的别名,被调函数中对形参的改变就是对实参变量的改变

对顺序表的初始化操作

Status InitList(SqList *L){  //此函数对形参作出了改动,将更改后的数据"回传"给主调函数的实参
//也可以在C++中使用&引用 Status InitList(SqList &L)

	//修改了结构体中的length,需要"回传",因为主调函数后面需要输出L.length
    L->length=0;	//等价于 (*L).length=0 解引用L获得其对应的存储内容
    return OK;
}

int main(){
	...
	SqList L;
    Status i;
    //可以在C++中使用 i=InitList(T);
    i=InitList(&L);	
    //&L:获得L的存储地址,将此存储地址传给被调函数中的指针变量*L,从而获取到被调函数改动后的L(所以可以理解为"回传")
    printf("初始化L后:L.length=%d\n",L.length); //这里L为改动后的值
    ...
    return 0;
}

对顺序表的插入操作

Status ListInsert(SqList *L,int i,ElemType e){ 	
	//此被调函数中没有对e作出改动,无需 "回传" 给主调函数的实参
	//此被调函数中对L作出了改动,需要将更改后的数据回传给主调函数的实参,故不能使用普通类型(无法“回传”)
	
	...
	if (i<=L->length)        
	{
		for(k=L->length-1;k>=i-1;k--)  
			L->data[k+1]=L->data[k];	//对结构体中的data进行了改动
	}
	L->data[i-1]=e;          
	L->length++;

	return OK;
}

int main(){
	SqList L;
	Status i;
    int j;
	for(j=1;j<=5;j++)
        i=ListInsert(&L,1,j);	
        //&L:获得L的存储地址,将此存储地址传给被调函数中的指针变量*L,从而获取到被调函数改动后的L(所以可以理解为"回传")
        //这里主调函数中的实参 j 直接传入被调函数中的形参e,被调函数中未对e进行改动,不必"回传"新数据给这里的主调函数
    printf("在L的表头插入0后:L.data=");
    ListTraverse(L); //对每个数据元素输出
    printf("L.length=%d \n",L.length);	//这里的L是更改过其data之后的那个顺序表("回传"的新L)
    ...
    return 0;
}

对顺序表的删除操作

Status ListDelete(SqList *L,int i,ElemType *e){ 
	//此被调函数对L和e均作出了改动
    int k;
    if (L->length==0)               
		return ERROR;
    if (i<1 || i>L->length)        
        return ERROR;
    *e=L->data[i-1];
    if (i<L->length)                
    {
        for(k=i;k<L->length;k++)
			L->data[k-1]=L->data[k];	//对结构体中的data进行了改动
    }
    L->length--;
    return OK;
}

int main(){   
    SqList L;
    ElemType e;
    ...
    
    ...
    j=5;
    ListDelete(&L,j,&e); /* 删除第5个数据 */
    //&L:获得L的存储地址,将此存储地址传给被调函数中的指针变量*L,从而获取到被调函数改动后的L(所以可以理解为"回传")
    //&e:获得e的存储地址,将此存储地址传给被调函数中的指针变量*e,从而获取到被调函数改动后的e(所以可以理解为"回传")
    printf("删除第%d个的元素值为:%d\n",j,e); //这里的e为"回传"的改变后的数据
    printf("依次输出L的元素:");
    ListTraverse(L); //对每个数据元素输出
    //这里的L是更改过其data之后的那个顺序表("回传"的新L)
    ...
    return 0;
}

总结:
只要被调函数中的操作需要改变结构体中的 data 或 length
被调函数的形参就要使用

SqList *L

在C++中使用&

SqList &L

如果不需要改变结构体中的 data 或 length
被调函数的形参使用

SqList L
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐