亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

C語言指針入門學習面面觀

2020-01-26 14:43:52
字體:
來源:轉載
供稿:網友

這似乎是一個很凝重的話題,但是它真的很有趣。

1. 指針是指向某一類型的東西,任何一個整體,只要能稱為整體就能擁有它自己的獨一無二的指針類型,所以指針的類型其實是近似無窮無盡的

2. 函數名在表達式中總是以函數指針的身份呈現,除了取地址運算符以及sizeof

3. C語言最晦澀難明的就是它復雜的聲明: void (*signal(int sig, void (*func)(int)))(int),試試著把它改寫成容易理解的形式

4. 對于指針,盡最大的限度使用const保護它,無論是傳遞給函數,還是自己使用

先來看看一個特殊的指針,姑且稱它為指針,因為它依賴于環境: NULL,是一個神奇的東西。先附上定義,在編譯器中會有兩種NULL(每種環境都有唯一確定的NULL):

#define NULL 0#define NULL ((void*)0)

有什么區別嗎?看起來沒什么區別都是0,只不過一個是常量,一個是地址為0的指針。

當它們都作為指針的值時并不會報錯或者警告,即編譯器或者說C標準認為這是合法的:

int* temp_int_1 = 0; //無警告int* temp_int_2 = (void*)0; //無警告int* temp_int_3 = 10; //出現警告

為什么?為什么0可以賦值給指針,但是10卻不行?他們都是常量。

因為C語言規定當處理上下文的編譯器發現常量0出現在指針賦值的語句中,它就作為指針使用,似乎很扯淡,可是卻是如此。

回到最開始,對于NULL的兩種情況,會有什么區別?拿字符串來說,實際上我是將字符數組看作是C風格字符串。

在C語言中,字符數組是用來存儲一連串有意義的字符,默認在這些字符的結尾添加'/0',好這里又出現了一個0值。

對于某些人,在使用字符數組的時候總是分不清楚NULL與'/0'的區別而誤用,在字符數組的末尾使用NULL是絕對錯誤的!雖然它們的本質都是常量0,但由于位置不同所以含義也不同。

開胃菜已過

對于一個函數,我們進行參數傳遞,參數有兩種形式: 形參與實參

int function(int value){    /*...*/}//...function(11);

其中,value是形參,11是實參,我們知道場面上,C語言擁有兩種傳遞方式:按值傳遞和按址傳遞,但是你是否有認真研究過?這里給出一個實質,其實C語言只有按值傳遞,所謂按址傳遞只不過是按值傳遞的一種假象。至于原因稍微一想便能明白。

對于形參和實參而言兩個關系緊密,可以這么理解總是實參將自己的一份拷貝傳遞給形參,這樣形參便能安全的使用實參的值,但也帶給我們一些麻煩,最經典的交換兩數

void swap_v1(int* val_1, int* val_2){  int temp = *val_1;  *val_1 = *val_2;  *val_2 = *val_1;}

這就是所謂的按址傳遞,實際上只是將外部指針(實參)的值做一個拷貝,傳遞給形參val_1與val_2,實際上我們使用:

#define SWAP_V2(a, b) (a += b, b = a - b, a -= b)#define SWAP_V3(x, y) {x ^= y; y ^= x; x ^= y}

試一試是不是很神奇,而且省去了函數調用的時間,空間開銷。上述兩種寫法的原理實質是一樣的。

但是,動動腦筋想一想,這種寫法真的沒有瑕疵嗎?如果輸入的兩個參數本就指向同一塊內存,會發生什么?

...int test_1 = 10, test_2 = 100;SWAP_V2(test_1, test_2);          printf("Now the test_1 is %d, test_2 is %d/n", test_1, test_2);.../*恢復原值*/SWAP_V2(test_1, test_1);printf("Now the test_1 is %d/n", test_1);  

會輸出什么?:

$: Now the test_1 is 100, test_2 is 10$: Now the test_1 is 0

對,輸出了0,為什么?稍微動動腦筋就能相通,那么對于后面的SWAP_V3亦是如此,所以在斟酌之下,解決方案應該盡可能短小精悍:

static inline void swap_final(int* val_1, int* val_2){  if(val_1 == val_2)    return;  *val_1 ^= *val_2;  *val_2 ^= *val_1;  *val_1 ^= *val_2;}#define SWAP(x, y) /do{         /  if(&x == &y)  /    break;   /  x ^= y;   /  y ^= x;   /  x ^= y;   /}while(0)

這便是目前能找到最好的交換函數,我們在此基礎上可以考慮的更深遠一些,如何讓這個交換函數更加通用?即適用范圍更大?暫不考慮浮點類型。 提示:可用void*

與上面的情況類似,偶爾的不經意就會造成嚴重的后果:

int combine_1(int* dest, int* add){  *dest += *add;  *dest += *add;  return *dest;}int combine_2(int* dest, int* add){  *dest = 2* (*add);//在不確定優先級時用括號是一個明智的選擇  return *dest;}

上述兩個函數的功能一樣嗎?恩看起來是一樣的

int test_3 = 10, test_4 = 100;combine_1(&test_3, &test_4);printf("After combine_1, test_3 = %d/n",test_3);.../*恢復原值*/combine_2(&test_3, &test_4);printf("After combine_2, test_3 = %d/n",test_3);

輸出

$: After combine_1, test_3 = 210$: After combine_2, test_3 = 210

如果傳入兩個同一對象呢?

... /*恢復test_3原值*/combine_1(&test_3, &test_3);printf("After second times combine_1, test_3 = %d/n",test_3);...combine_2(&test_3, &test_3);printf("After second times combine_2, test_3 = %d/n",test_3);

輸出

$: After second times combine_1, test_3 = 30$: After second times combine_2, test_3 = 20

知道真相總是令人吃驚,指針也是那么令人又愛又恨。

C99 標準之后出現了一個新的關鍵字, restrict,被用于修飾指針,它并沒有太多的顯式作用,甚至加與不加,在 你自己 看來,效果毫無區別。但是反觀標準庫的代碼中,許多地方都使用了該關鍵字,這是為何

  • 首先這個關鍵字是寫給編譯器看的
  • 其次這個關鍵字的作用在于輔助編譯器更好的優化該程序
  • 最后,如果不熟悉,絕對不要亂用這個關鍵字。

關于數組的那些事

數組和指針一樣嗎?

不一樣

要時刻記住,數組與指針是不同的東西。但是為什么下面代碼是正確的?

int arr[10] = {10, 9, 8, 7};int* parr = arr;

我們還是那句話,結合上下文,編譯器推出 arr處于賦值操作符的右側,默默的將他轉換為對應類型的指針,而我們在使用arr時也總是將其當成是指向該數組內存塊首位的指針。

//int function2(const int test_arr[10]//int function2(const int test_arr[]) 考慮這三種寫法是否一樣int function2(const int* test_arr){  return sizeof(test_arr);}...int size_out = sizeof(arr);int size_in = function2(arr);printf("size_out = %d, size_in = %d/n", size_out, size_in);

輸出:

size_out = 40, size_in = 8

這就是為什么數組與指針不同的原因所在,在外部即定義數組的代碼塊中,編譯器通過上下文發覺此處arr是一個數組,而arr代表的是一個指向10個int類型的數組的指針,只所謂最開始的代碼是正確的,只是因為這種用法比較多,就成了標準的一部分。就像世上本沒有路,走的多了就成了路。"正確"的該怎么寫

int (*p)[10] = &arr;

此時p的類型就是一個指向含有10個元素的數組的指針,此時(*p)[0]產生的效果是arr[0],也就是parr[0],但是(*p)呢?這里不記錄,結果是會溢出,為什么?

這就是數組與指針的區別與聯系,但是既然我們可以使用像parr這樣的指針,又為什么要寫成int (*p)[10]這樣丑陋不堪的模式呢?原因如下:

回到最開始說過的傳遞方式,按值傳遞在傳遞arr時只是純粹的將其值進行傳遞,而丟失了上下文的它只是一個普通指針,只不過我們程序員知道它指向了一塊有意義的內存的起始位置,我想要將數組的信息一起傳遞,除了額外增加一個參數用來記錄數組的長度以外,也可以使用這個方法,傳遞一個指向數組的指針 這樣我們就能只傳遞一個參數而保留所有信息。但這么做的也有限制:對于不同大小,或者不同存儲類型的數組而言,它們的類型也有所不同

 int arr_2[5]; int (*p_2)[5] = &arr_2; float arr_3[5]; float (*p_3)[5] = &arr_3;

如上所示,指向數組的指針必須明確指定數組的大小,數組存儲類型,這就讓指向數組的指針有了比較大的限制。

這種用法在多維數組中使用的比較多,但總體來說平常用的并不多,就我而言,更傾向于使用一維數組來表示多維數組,實際上誠如前面所述,C語言是一個非常簡潔的語言,它沒有太多的廢話,就本質而言C語言并沒有多維數組,因為內存是一種線性存在,即便是多維數組也是實現成一維數組的形式。

就多維數組在這里解釋一下。所謂多維數組就是將若干個降一維的數組組合在一起,降一維的數組又由若干個更降一維的數組組合在一起,直到最低的一維數組,舉個例子:

int dou_arr[5][3];

就這個二維數組而言,將5個每個為3個int類型的數組組合在一起,要想指向這個數組該怎么做?

  int (*p)[3]    = &dou_arr[0];  int (*dou_p)[5][3] = &dou_arr;  int (*what_p)[3]  = dou_arr;

實際上多維數組只是將多個降一維的數組組合在一起,令索引時比較直觀而已。當真正理解了內存的使用,反而會覺得多維數組帶給自己更多限制 對于第三句的解釋,當數組名出現在賦值號右側時,它將是一個指針,類型則是 指向該數組元素的類型,而對于一個多維數組來說,其元素類型則是其降一維數組,即指向該降一維數組的指針類型。這個解釋有點繞,自己動手寫一寫就好很多。

對于某種形式下的操作,我們總是自然的將相似的行為結合在一起考慮。考慮如下代碼:

int* arr_3[5] = {1, 2, 3, 4, 5};int* p_4   = arr_3;printf("%d == %d == %d ?/n", arr_3[2], *(p_4 + 2), *(arr_3 + 2));

輸出: 3 == 3 == 3 ? 實際上對于數組與指針而言, []操作在大多數情況下都能有相同的結果,對于指針而言*(p_4 + 2)相當于p_4[2],也就是說[]便是指針運算的語法糖,有意思的是2[p_4]也相當于p_4[2],"Iamastring"[2] == 'm',但這只是娛樂而已,實際中請不要這么做,除非是代碼混亂大賽或者某些特殊用途。 在此處,應該聲明的是這幾種寫法的執行效率完全一致,并不存在一個指針運算便快于[]運算,這些說法都是上個世紀的說法了,隨著時代的發展,我們應該更加注重代碼整潔之道

在此處還有一種奇異又實用的技巧,在char數組中使用指針運算進行操作,提取不同類型的數據,或者是在不同類型數組中,使用char*指針抽取其中內容,才是顯示指針運算的用途。但在使用不同類型指針操作內存塊的時候需要注意,不要操作無意義的區域或者越界操作。

實際上,最簡單的安全研究之一,便是利用溢出進行攻擊。

Advance:對于一個函數中的某個數組的增長方向,總是向著返回地址的,中間可能隔著許多其他自動變量,我們只需要一直進行溢出試驗,直到某一次,該函數無法正常返回了!那就證明我們找到了該函數的返回地址存儲地區,這時候我們可以進行一些操作,例如將我們想要的返回地址覆蓋掉原先的返回地址,這就是所謂的溢出攻擊中的一種。

內存的使用的那些事兒

你一直以為你操作的是真實物理內存,實際上并不是,你操作的只是操作系統為你分配的資格虛擬地址,但這并不意味著我們可以無限使用內存,那內存賣那么貴干嘛,實際上存儲數據的還是物理內存,只不過在操作系統這個中介的介入情況下,不同程序窗口(可以是相同程序)可以共享使用同一塊內存區域,一旦某個傻大個程序的使用讓物理內存不足了,我們就會把某些沒用到的數據寫到你的硬盤上去,之后再使用時,從硬盤讀回。這個特性會導致什么呢?假設你在Windows上使用了多窗口,打開了兩個相同的程序:

...int stay_here;char tran_to_int[100];printf("Address: %p/n", &stay_here);fgets(tran_to_int, sizeof(tran_to_int), stdin);sscanf(tran_to_int, "%d", &stay_here);for(;;){  printf("%d/n", stay_here);  getchar();  ++stay_here;}...

對此程序(引用前橋和彌的例子),每敲擊一次回車,值加1。當你同時打開兩個該程序時,你會發現,兩個程序的stay_here都是在同一個地址,但對它進行分別操作時,產生的結果是獨立的!這在某一方面驗證了虛擬地址的合理性。虛擬地址的意義就在于,即使一個程序出現了錯誤,導致所在內存完蛋了,也不會影響到其他進程。對于程序中部的兩個讀取語句,是一種理解C語言輸入流本質的好例子,建議查詢用法,這里稍微解釋一下:

通俗地說,fgets將輸入流中由調用起,stdin輸入的東西存入起始地址為tran_to_int的地方,并且最多讀取sizeof(tran_to_int)個,并在后方sscanf函數中將剛才讀入的數據按照%d的格式存入stay_here,這就是C語言一直在強調的流概念的意義所在,這兩個語句組合看起來也就是讀取一個數據這么簡單,但是我們要知道一個問題,一個關于scanf的問題

 scanf("%d", &stay_here);

這個語句將會讀取鍵盤輸入,直到回車之前的所有數據,什么意思?就是回車會留在輸入流中,被下一個輸入讀取或者丟棄。這就有可能會影響我們的程序,產生意料之外的結果。而使用上當兩句組合則不會。

函數與函數指針的那些事

事實上,函數名出現在賦值符號右邊就代表著函數的地址

int function(int argc){ /*...*/}...int (*p_fun)(int) = function;int (*p_fuc)(int) = &function;//和上一句意義一致

上述代碼即聲明并初始化了函數指針,p_fun的類型是指向一個返回值是int類型,參數是int類型的函數的指針

p_fun(11);(*p_fun)(11);function(11);

上述三個代碼的意義也相同,同樣我們也能使用函數指針數組這個概念

int (*p_func_arr[])(int) = {func1, func2,};

其中func1,func2都是返回值為int參數為int的函數,接著我們能像數組索引一樣使用這個函數了。

Tips: 我們總是忽略函數聲明,這并不是什么好事。

在C語言中,因為編譯器并不會對有沒有函數聲明過分深究,甚至還會放縱,當然這并不包含內聯函數(inline),因為它本身就只在本文件可用。
比如,當我們在某個地方調用了一個函數,但是并沒有聲明它:

 CallWithoutDeclare(100); //參數100為 int 型

那么,C編譯器就會推測,這個使用了int型參數的函數,一定是有一個int型的參數列表,一旦函數定義中的參數列表與之不符合,將會導致參數信息傳遞錯誤(編譯器永遠堅信自己是對的!),我們知道C語言是強類型語言,一旦類型不正確,會導致許多意想不到的結果(往往是Bug)發生。

對函數指針的調用同樣如此
C語言中malloc的那些事兒

我們常常見到這種寫法:

int* pointer = (int*)malloc(sizeof(int));

這有什么奇怪的嗎?看下面這個例子:

int* pointer_2 = malloc(sizeof(int));

哪個寫法是正確的?兩個都正確,這是為什么呢,這又要追求到遠古C語言時期,在那個時候, void* 這個類型還沒有出現的時候,malloc 返回的是 char* 的類型,于是那時的程序員在調用這個函數時總要加上強制類型轉換,才能正確使用這個函數,但是在標準C出現之后,這個問題不再擁有,由于任何類型的指針都能與 void* 互相轉換,并且C標準中并不贊同在不必要的地方使用強制類型轉換,故而C語言中比較正統的寫法是第二種。

題外話: C++中的指針轉換需要使用強制類型轉換,而不能像第二種例子,但是C++中有一種更好的內存分配方法,所以這個問題也不再是問題。

Tips:

C語言的三個函數malloc, calloc, realloc都是擁有很大風險的函數,在使用的時候務必記得對他們的結果進行校驗,最好的辦法還是對他們進行再包裝,可以選擇宏包裝,也可以選擇函數包裝。
realloc函數是最為人詬病的一個函數,因為它的職能過于寬廣,既能分配空間,也能釋放空間,雖然看起來是一個好函數,但是有可能在不經意間會幫我們做一些意料之外的事情,例如多次釋放空間。正確的做法就是,應該使用再包裝閹割它的功能,使他只能進行擴展或者縮小堆內存塊大小。
指針與結構體

typedef struct tag{    int value;    long vari_store[1];}vari_struct;

乍一看,似乎是一個很中規中矩的結構體

...vari_struct vari_1;vari_struct* vari_p_1 = &vari_1;vari_struct* vari_p_2 = malloc(sizeof(vari_struct))(

似乎都是這么用的,但總有那么一些人想出了一些奇怪的用法

int     what_spa_want = 10;vari_struct* vari_p_3 = malloc(sizeof(vari_struct) + sizeof(long)*what_spa_want);

這么做是什么意思呢?這叫做可變長結構體,即便我們超出了結構體范圍,只要在分配空間內,就不算越界。what_spa_want解釋為你需要多大的空間,即在一個結構體大小之外還需要多少的空間,空間用來存儲long類型,由于分配的內存是連續的,故可以直接使用數組vari_store直接索引。 而且由于C語言中,編譯器并不對數組做越界檢查,故對于一個有N個數的數組arr,表達式&arr[N]是被標準允許的行為,但是要記住arr[N]卻是非法的。 這種用法并非是娛樂,而是成為了標準(C99)的一部分,運用到了實際中

對于內存的理解

在內存分配的過程中,我們使用 malloc 進行分配,用 free 進行釋放,但這是我們理解中的分配與釋放嗎? 在調用 malloc 時,該函數或使用 brk() 或使用 nmap() 向操作系統申請一片內存,在使用時分配給需要的地方,與之對應的是 free,與我們硬盤刪除東西一樣,實際上:

int* value = malloc(sizeof(int)*5);...free(value);printf("%d/n", value[0]);

代碼中,為什么在 free 之后,我又繼續使用這個內存呢?因為 free 只是將該內存標記上釋放的標記,示意分配內存的函數,我可以使用,但并沒有破壞當前內存中的內容,直到有操作對它進行寫入。 這便引申出幾個問題:

Bug更加難以發現,讓我們假設,如果我們有兩個指針p1,p2指向同一個內存,如果我們對其中某一個指針使用了 free(p1); 操作,卻忘記了還有另一個指針指向它,那這就會導致很嚴重的安全隱患,而且這個隱患十分難以發現,原因在于這個Bug并不會在當時顯露出來,而是有可能在未來的某個時刻,不經意的讓你的程序崩潰。
有可能會讓某些問題更加簡化,例如釋放一個條條相連的鏈表域。
總的來說,還是那句話C語言是一把雙刃劍。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品国产亚洲伊人久久| 欧美日韩中国免费专区在线看| 久久久www成人免费精品张筱雨| 中文国产亚洲喷潮| 欧美放荡办公室videos4k| 国产精品户外野外| 亚洲视频在线观看| 青青在线视频一区二区三区| 国产自产女人91一区在线观看| 性色av一区二区三区红粉影视| 成人精品网站在线观看| 国产99久久精品一区二区| 国产在线久久久| 成人av.网址在线网站| 国产精品aaaa| 欧美剧在线观看| 欧美性一区二区三区| 欧美极品少妇全裸体| 黄色成人av在线| 国产一区二区精品丝袜| 国产日韩在线免费| 欧美激情精品久久久久久| 亚洲女人被黑人巨大进入al| 色诱女教师一区二区三区| 成人网在线免费观看| 久久免费视频网| 国产成人小视频在线观看| 国产一区欧美二区三区| 国产a级全部精品| 国产精品九九久久久久久久| 亚洲黄色av网站| 亚洲国产精品久久久久久| 欧美精品在线免费| 国产精品久久一区| 国产精品一区二区av影院萌芽| 国产丝袜视频一区| 成人自拍性视频| 久久久av亚洲男天堂| 日韩成人性视频| 亚洲欧美国产视频| 黄色成人av网| 欧美大片在线看| www.亚洲人.com| 国产一区玩具在线观看| 国产精品人成电影| 欧美日韩国产影院| 国产有码一区二区| 青青久久av北条麻妃黑人| 欧美巨乳在线观看| 国产一区二区三区在线观看视频| 久久久久一本一区二区青青蜜月| 日日噜噜噜夜夜爽亚洲精品| 亚洲福利视频免费观看| 日韩一区二区福利| 538国产精品视频一区二区| 日韩精品在线观看视频| 欧美疯狂xxxx大交乱88av| 欧美激情成人在线视频| 91久久久国产精品| 亚洲男人av在线| 精品久久久999| 2019国产精品自在线拍国产不卡| 色综合影院在线| 一区二区三区四区视频| 91精品国产自产91精品| 国产精品成人免费视频| 久久久免费电影| 色综合天天狠天天透天天伊人| 日韩欧美a级成人黄色| 久久久久国产一区二区三区| 亚洲视频在线免费观看| 国产欧洲精品视频| 国产成人97精品免费看片| 日韩欧美精品中文字幕| 久久久久国产精品免费| 成人激情视频免费在线| 国产精品精品一区二区三区午夜版| 日韩综合视频在线观看| 国产精品自产拍高潮在线观看| 久久精品久久久久电影| 欧美成人精品在线| 精品日本高清在线播放| 亚洲人成绝费网站色www| 亚洲欧洲一区二区三区在线观看| 久久网福利资源网站| 欧美性xxxxxx| 日韩在线视频观看正片免费网站| 激情久久av一区av二区av三区| 日本乱人伦a精品| 久久亚洲影音av资源网| 福利微拍一区二区| 亚洲国产日韩欧美在线动漫| 亚洲人在线观看| 国产视频在线一区二区| 欧美丝袜一区二区三区| 97视频在线观看免费高清完整版在线观看| 国产成人鲁鲁免费视频a| 欧美精品在线观看| 欧美日韩国产在线播放| 欧美国产在线视频| 中文字幕av一区中文字幕天堂| 在线成人一区二区| 中文字幕欧美精品日韩中文字幕| 日韩中文有码在线视频| 亚洲欧美日韩天堂| 国产一区二区三区在线观看视频| 国产成人自拍视频在线观看| 欧美性xxxxx极品娇小| 欧美一区二区三区四区在线| 亚洲欧美制服中文字幕| 亚洲综合最新在线| 国产精品免费观看在线| 在线激情影院一区| 国产噜噜噜噜噜久久久久久久久| 欧美极品少妇xxxxⅹ喷水| 福利视频导航一区| 精品亚洲一区二区三区四区五区| 亚洲毛片一区二区| 成人疯狂猛交xxx| 国产+成+人+亚洲欧洲| 久久久日本电影| 中文字幕亚洲欧美日韩2019| 最新国产精品亚洲| 久久亚洲私人国产精品va| 亚洲精品99久久久久| 韩剧1988免费观看全集| xxxxx成人.com| 日韩精品在线观看一区| 中文字幕一区日韩电影| 亚洲成人精品久久久| 亚洲国产精品系列| 欧美国产日韩中文字幕在线| 欧美激情视频在线| 韩曰欧美视频免费观看| 久久久免费高清电视剧观看| 久久视频在线观看免费| 中文字幕亚洲第一| 日韩精品小视频| 欧美日韩免费在线观看| 高清一区二区三区日本久| 国产精彩精品视频| 亚洲国产高清福利视频| 亚洲成av人片在线观看香蕉| 欧美日韩中文字幕在线| 日韩精品在线观看一区二区| 91免费国产视频| 久久久国产视频| 亚洲aⅴ男人的天堂在线观看| 亚洲亚裔videos黑人hd| 成人免费视频网| 久久精品一偷一偷国产| 奇米四色中文综合久久| 欧美日韩国产区| 国产精品爱啪在线线免费观看| 日韩经典一区二区三区| 久久精品成人一区二区三区| 亚洲欧美制服丝袜| 久久久成人的性感天堂| 成人午夜在线视频一区| 国产精品入口夜色视频大尺度| 中文字幕亚洲欧美一区二区三区| 91美女片黄在线观| 亚洲跨种族黑人xxx| 国产精品无av码在线观看|