在資料結構與演算法中 傳值方式(C語言)

宗谷發表於2022-03-19

傳值方式

前言

當初學順序連結串列的時候,書上就出現了這樣的語言,如下所示:

Status InitList_Sq(SqList &L) {
	//構造一個空的線性表L。
	L.elem = (ElemType *)malloc(LIST_INIT_SIZE* sizeof(ElemType));
	if(!L.elem)exit(OVERFLOW);
	L.length=0;
	L.listsize=LIST_INIT_SIZE;
	return OK;
}

這裡面的&L第一遍看的時候想當然的認為是取了SqList結構體的L的地址,沒有細想。然後又看到了這句。

Status GetElem(SqList L,int i,ElemType &e)   //這根本就不是取地址符

這裡的ElemType就是int的型別

那麼可以寫成如下這種方法

Status GetElem(SqList L,int i,int &e)

這樣整個倒是顯得非常奇怪

那麼我們類比這樣的形式

int *a,*b; /* 定義了兩個整型的指標 */
int **a, **b; /* 定義了整型指標的指標 */
//那麼難道說是定義了整型變數為地址的變數e
int &e;

那麼我們看下面他寫的這個東西:

顯然這裡可以看出由於L指標指向的是ElemType型別,所以e是ElemType型別的。所以以上類比顯然是不對的。

C/C++中的引用引數

查詢了很多的資料發現,這個實際上是C++裡的形參符號,必須要在跟在資料型別的後面使用。在函式內部對形參的操作都等同於直接操作原變數。

請看下面的例子

1.1 實參值不變

把實參的值傳送給函式區域性工作區相應的副本中,函式使用這個副本執行必要的功能。函式修改的是副本的值,實參的值不變。

#include <stdio.h>
void swap(float m,float n)
{
    float temp;
    temp = m;
    m = n;
    n = temp;
}
void main()
{
    float a,b;
    printf ("please enter the number of a and b =");
    scanf("%f %f",&a,&b);
    swap (a,b);
    printf ("the number of a = %f, the number of b = %f",a,b);
}

可以看到,a與b的值並沒有發生更換。

1.2傳地址方式——指標變數做引數,形參變化影響實參

#include <stdio.h>
void swap(float *m,float *n)
{
    float temp;
    temp = *m;      //取指標變數內容
    *m = *n;
    *n = temp;1 
}
void main()
{
    float a,b,*p1,*p2;
    printf ("please enter the number of a and b =");
    scanf("%f %f",&a,&b);
    p1=&a;
    p2=&b;
    swap (p1,p2);
    printf ("the number of a = %f, the number of b = %f",a,b);
}

還有第二種方式

#include <stdio.h>
// 利用指標的經典解法
void swap(int *a, int *b)
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void main()
{
    int a = 1, b = 2;
    swap(&a,&b);
    printf("%d %d",a,b);
}

可以看到,形參變化影響實參

形參變化不影響實參

#include <stdio.h>
void swap(float *a, float *b)
{
    float *temp;
    temp = a;
    a = b;
    b = temp;
}

void main()
{
    float a = 1, b = 2;
    swap(&a,&b);
    printf("%f %f",a,b);
}

可以發現ab值並沒有發生變化

1.4 傳地址方式——陣列名作引數

傳遞的是陣列的首地址 概念:陣列名就是陣列首地址

對形引數組所做的任何改變都將反映到實引數組中

#include <stdio.h>
#include <string.h>
void sub(char *b)   //在C++語言中也可以使用b[]來寫   
{
    strcpy(b,"world");
}
void main()
{
    char a[10] = "hello";
    sub(a);  //傳陣列首地址
    printf("%s",a);
}

1.5 傳地址方式——引用型別做引數

什麼是引用?

引用:他用來給一個物件提供一個代替的名字

//運用了C++的語法
#include <iostream>
#include <stdio.h>
// 引用引數實現交換
void swap(int &a, int &b){
    int temp;
    temp = a;
    a = b;
    b = temp;
}

// Using main to test
int main(){
	int a = 1, b = 2;
    swap(a,b);
    printf("%d %d\n",a,b);
    return 0;
}

有些文章說道,通過引用的方式傳遞給函式的是變數的地址,這種方式叫做地址傳遞方式,還提到這是和“值傳遞”十分不同的方式。
有些書說道:“引用實際上是取了個‘別名’
還有的書和文章說道引用是比通過指標傳遞更加高效的方式,因為不需要開闢新的記憶體空間用來拷貝實參的地址。

那麼SqList *&L和SqList *L的關係就能捋清楚了 可以參考1.2 傳地址方式——指標變數做引數,形參變化影響實參

SqList *&L的情況

它的意思是,L是對List的引用,函式體內對L的操作,就相當於對Head的操作,所以這種情況下對L的更改才會發生到List上。

SqList *L的情況

當List指標作為函式引數傳進去時,意為你要把指標List所指的地址值賦給指標L,(可以類比int型別,畢竟指標本質上也是一種資料型別)。這就意味著此時的實參List跟形參L並不是同一個指標,而是指向同一個地址的不同指標。所以你對L的操作並沒有發生到List身上。達不到預期效果。

最後

C語言不存在“引用”的概念,符號“&”只是表示取地址,而C++才有“引用”的含義。
比如對於這段程式碼——

//C語言不存在“引用”的概念,符號“&”只是表示取地址,而C++才有“引用”的含義。
//比如對於這段程式碼——
#include<stdio.h>
int main()
{
	int i = 0;
	int &j = i;
},
/*使用gcc編譯器編譯會報錯:”錯誤:expected identifier or ‘(’ before ‘&’ token“,但是使用g++編譯就不會報錯。*/

相關文章