在C C 中左值和右值得理解

2021-09-03 02:05:45 字數 3665 閱讀 6733

宣告:本文**  如果有侵犯他人版權,煩請告知,會立馬刪除。

左值就是在賦值中可以放在賦值操作符兩邊的值,比如: 

int a = 1; 

double b = 2.0 

a = b; 

b = a; 

這裡a和b都是左值,一切變數都是左值,但const變數是例外。 

*p是乙個左值,和變數一樣,只要在*p的右邊加上賦值運算子,就可改變*p的值。

如果p是乙個指向常量的指標,*p就是乙個不能修改的左值,即它不能被放到賦值運算子的左邊。

i和 -i 都是表示式 

但乙個是左值(i),乙個是右值(-i)。 

++,--這兩種操作符要求作用於左值,所以i++合法,(-i)++不合法。

不嚴謹的講,左值右值的區分在於位於等號的那一側,左側的是左值,通常是乙個變數,右側的是右值,可以是乙個變數,或者是乙個表示式。 

先看什麼是表示式: 

表示式由乙個或多個運算元通過操作符組合而成。最簡單的表示式僅包含乙個字面值常量或變數。較複雜的表示式則由操作符以及乙個或多個運算元構成。 

再看什麼是左值: 

c++ 中存在兩種表示式:左值可以出現在賦值語句的左邊或右邊。右值只能出現在賦值的右邊,不能出現在賦值語句的左邊。 

另外說明一下,i不僅是乙個表示式,它還是乙個變數,但是-i卻不是乙個變數,這是他們乙個可以自增乙個不能自增的根本原因 

對於i++來說,i是乙個變數,所以是乙個左值,執行i=i+1 

但是對於(-i)++來說,-i是乙個表示式,而不是乙個變數,乙個表示式是不可以作為左值的,因為沒有辦法執行這條語句:-i=-i+1(-i+1的值不能附給-i,因為沒有-i這個變數儲存空間) 

乙個賦值表示式: 

x = y; 

在這個表示式裡,符號x的含義是x所代表的位址,這被稱為左值,左值在編譯時可知,左值表示儲存結果的地方; 

在這個表示式裡,符號y的含義是y所代表的位址的內容,這被稱為右值,右值在執行時才可知,如無特別說明,右值表示「y的內容」。 在《c專家程式設計(中文版)》中第4章,對左值和右值的基本描述。 

而右值則是只可以放在賦值操作符右邊的值,比如: 

int a = 0; 

char *b = "hello"; 

3 = a; // error 

"howdy" = b // error 

這裡3和"howdy"都是右值,所以不能放在賦值操作符左邊,一切常數、字元和字串都是右值。

l-value 與 r-value 區別

左值是引用某個物件的表示式,就是可以放在賦值左邊的東西,如:*(p+1)=7, 沒有名字的變數(*(p+1)表示式一定是乙個型別的物件)被賦值了,但左值並不一定能被賦值,因為左值可以引用某個常量。 所有的引用都是左值。 

右值是表示式的值(不是引用),可以放在賦值右面。 

所有的左值都可以是右值,反之不成立 

int i, j, *p; 

i = 7; // correct. a variable name, i, is an l-value. 

7 = i; // error. a constant, 7, is an r-value. 

j * 4 = 7; // error. the expression j * 4 yields an r-value. 

*p = i; // a dereferenced pointer is an l-value. 

const int ci = 7; // declare a const variable. 

ci = 9; // error. ci is a nonmodifiable l-value

普通引用和const引用的初始化 

當引用的初始式是乙個左值(是乙個物件,你可以取得他的位址)時,其初始化就是非常簡單的事情。普通t&的初始式必須是乙個t型別的。而cosnt t&則不必是乙個左值,甚至可以不是t型別的。在這樣的情況下,經過以下幾個步驟。

(1)首先,如果需要的話,將應用到型別t的隱式型別轉換。

(2)而後,將結果存入乙個型別t的臨時變數。

(3)最後,將此臨時變數用作初始化的值。

例如double& d=1; //錯誤,d是左值,不能用右值1 來初始化

const double& cd=1; //ok

對後乙個初始化的解釋是:

double temp=double(1); //首先建立乙個具有正確資料型別的臨時變數

const double& cd=temp; //而後用這個臨時變數作為cd的初始式,temp是個右值

由於左值的一大特點是可以對其賦值,而const正好將這個特點給閹割了,使該表示式成為了乙個右值,所以可以用右值來初始化。

===7.3.1引用引數===

函式的引用引數

把引數宣告成引用,實際上改變了預設的按值傳遞引數的傳遞機制。在按值傳遞時,函式操縱的是實參的本地拷貝。當引數是引用時,函式接收的是實參的左值而不是值的拷貝。

這意味著函式知道實參在記憶體中的位置,因而能夠改變它的值或取它的位址。

int obj;

void frd( double & );

int main() 

對frd()的呼叫是錯誤的.實參型別是int 必須被轉換成double 以匹配引用引數的型別,

該轉換的結果是個臨時值,因為這種引用不是const 型的,所以臨時值(不是左值)不能被用來初始化該引用

什麼時候將乙個引數指定為引用比較合:

1、允許改變實參的值

2、向主調函式返回額外的結果

3、向函式傳遞大型類物件

使用指標還是引用作為引數的乙個重要區分:

引用必須被初始化為指向乙個物件,一旦初始化了,它就不能再指向其他物件,而指標可以指向一系列不同的物件也可以什麼都不指向

所以,如果乙個引數可能在函式中指向不同的物件,或者這個引數可能不指向任何物件,則必須使用指標引數

===7.3.3 陣列引數===

在c++中陣列永遠不會按值傳遞它是傳遞第乙個元素(準確地說是第0 個)的指標

如下宣告

void putvalues( int[ 10 ] ); //當編譯器對實參型別進行引數型別檢查時,並不檢查陣列的長度,編澤器忽略10

被編譯器視為

void putvalues( int* );

陣列的長度與引數宣告無關,因此下列三個宣告是等價的

// 三個等價的putvalues()宣告

void putvalues( int* );

void putvalues( int );

void putvalues( int[ 10 ] );

傳遞陣列長度的三種機制

1、提供乙個含有陣列長度的額外引數:void putvalues( int, int size );

2、將引數宣告為陣列的引用:void putvalues( int (&arr)[10] );

當引數是乙個陣列型別的引用時,陣列長度成為引數和實參型別的一部分,編譯器檢查陣列實參的長度與在函式引數型別中指定的長度是否匹配

// 引數為10 個int 的陣列

// parameter is a reference to an array of 10 ints

void putvalues( int (&arr)[10] );//只接受10 個int的陣列

int main()

3、使用抽象容器

void putvalues(const vector&vec );

理解C 中的左值和右值

理解c 中的左值和右值 attention this blog is a translation of which is posted by internalpoiners.一 前言 一直以來,我都對c 中左值 lvalue 和右值 lvalue 的概念模糊不清。我認為是時候好好理解他們了,因為這些...

對左值和右值的理解

來自 今天在csdn上看到乙個關於左值和右值討論貼,順便說下自己的理解 左值 必須要有明確的名字來代表這個值 右值 如果沒有明確的名字來代表這個值,那麼這個就是只能是右值 舉例 int a 1 a,a 2,a都可以是左值 而1,a 就不能作為左值,只能是右值 關於a a a 是先取a的乙個副本,然後...

左值和右值,左值引用和右值引用

左值 lvalue 這一術語 於c語言,用來指代那些可以用在賦值表示式左側的東西,具名物件 在棧和堆上分配的物件,或者其他物件的成員,總之就是又確定儲存空間的東西。而術語右值 rvalue 也是源自c語言,指的是只能在賦值表示式右側出現的東西,如字面值和臨時物件。只能繫結到左值,不能繫結到右值的引用...