国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

C語言進階:指針進階續

ingood / 1511人閱讀

摘要:故使用無具體類型,又稱通用類型,即可以接收任意類型的指針,但是無法進行指針運算解引用,整數等。求指針所占字節而不是解引用訪問權限大小。數組就是整個數組的大小,數組元素則是數組元素的大小,指針大小都為。

指針進階續

續前文《C語言進階:指針進階》

回調函數

回調函數定義

回調函數:通過函數指針調用的函數,或者說使用函數指針調用函數這樣的機制被稱為回調函數。回調函數不由實現方直接調用,而是作為特殊條件下的響應。

概念無關緊要,理解并熟練運用這種方法才更為重要。

快速排序 qsort

qsort函數邏輯
void qsort(void* base, size_t num, size_t width, int (*cmp)(const void* e1, const void* e2));

qsort無返回值,有四個參數。分別為base:起始地址,num:元素個數,width:元素大小以及compare:比較函數。可與冒泡排序作對比。

//冒泡排序void Bubble_sort(int arr[], int sz) {	for (int i = 0; i < sz - 1; i++) { 		for (int j = 0; j < sz - 1 - i; j++) { 			//比較函數			if (arr[j] > arr[j + 1]) {				int tmp = arr[j];				arr[j] = arr[j + 1];				arr[j + 1] = tmp;			}        }    }}

與冒泡排序作對比發現,冒泡排序僅需起始地址和元素個數即可,暗含了其他信息。由于過度具體化,冒泡排序只能排序整型數組,且比較函數過于簡單無需多帶帶列出。

因為qsort排序可適用于多種類型如浮點型,字符型,自定義類型的數據,故無法規定具體類型,所以需要多個參數去描述元素的基本信息。

qsort之所以能夠適應多種數據,是因為參數void* base再搭配上numwidth就描述出任意一種類型。

為什么將參數base的類型定義為void*呢?如下述代碼所示。

char* p1 = &a;//從int*到char*類型不兼容char* p2 = &f;//從float*到char*類型不兼容void* p1 = &a;void* p2 = &f;

確定類型的地址之間直接賦值會提示類型不兼容,強制轉化也可能會導致精度丟失。

故使用無(具體)類型void*,又稱通用類型,即可以接收任意類型的指針,但是無法進行指針運算(解引用, ± ± ±整數等)。

p1++;   *p1;   p1 - p2;   p1 > p2;//表達式必須是指向完整對象類型的指針
  1. base:用于存入數據的起始地址。類型定義為void*,可接受任意類型的指針。

  2. num:待排序的元素個數。

  3. width:元素寬度,所占字節大小。

明確了排序的起始位置,元素個數和元素大小,貌似已經夠了。但是并無法排序所有類型,因此必須自定義一個抽象的比較函數指定元素的比較方式。

  1. cmp:比較函數,用于指定元素的比較方式。

    • elem1小于elem2,返回值小于0
    • elem1大于elem2,返回值大于0
    • elem1等于elem2,返回值為0
  2. elem1elem2:進行比較的兩個元素的地址作參數。

qsort可以說是一個半庫函數半自定義函數。自定義在于其函數最后一個參數為比較函數,該函數內部實現自由,但返回值必須按照規定返回相應的數值。

小結

需要qsort函數排序各種類型的數據,

  • base起始地址不可為固定的指針類型,只能用void*
  • 既然是通用類型還要明確比較元素的個數和大小。
  • 最后,排序最核心的比較大小,為適應不同的類型元素必須自定義專門的比較函數。
qsort實現冒泡排序
//比較函數:整型#include int int_cmp(const void* e1, const void* e2) {	return *(int*)e1 - *(int*)e2;}int main() {	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };	int sz = sizeof(arr) / sizeof(arr[0]);	qsort(arr, sz, sizeof(arr[0]), int_cmp);	return 0;}

比較函數int_com不需要傳參,作為回調函數由qsort直接調用。比較函數的傳參過程由qsort內部實現。

qsort實現結構體排序
#include struct stu {	char* name;	short age;	float score;};//按照成績排序int score_cmp(const void* e1, const void* e2) {	//1.升序    return ((struct stu*)e1)->score - ((struct stu*)e2)->score;	//2.降序    return ((struct stu*)e2)->score - ((struct stu*)e1)->score;}//按照名字排序int name_cmp(const void* e1,const void* e2) {	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);}int main() {	struct stu s[3] = {         { "張三", 22, 99.5f },{ "李四", 21, 66.4f },{ "王五", 18, 80.1f }     };	int sz = sizeof(s) / sizeof(s[0]);	//1.    qsort(s, sz, sizeof(s[0]), name_cmp);	//2.    qsort(s, sz, sizeof(s[0]), score_cmp);	return 0;}

由此可得,提取出一個比較函數,具體交換的方式由qsort內部實現。

模擬實現qsort

qsort的函數邏輯,實現冒泡排序。

//打印函數void print_arr(int arr[],int sz) {	for (int i = 0; i < sz; i++) {		printf("%d ", arr[i]);	}}//交換函數void Swap(char* buf1, char* buf2, size_t width) {	for (size_t i = 0; i < width; i++) {//寬度次		char tmp = *buf1;		*buf1 = *buf2;		*buf2 = tmp;		buf1++;		buf2++;	}}//比較函數int cmp(const void* e1, const void* e2) {	return *(int*)e1 - *(int*)e2;}//排序函數void my_bubble_sort(void* base, size_t num, size_t width, int(*cmp)(const void* e1, const void* e2)) {	for (size_t i = 0; i < num - 1; i++) {		for (size_t j = 0; j < num - 1 - i; j++) {			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0) {//以字節為單位				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);			}		}	}}int main() {	int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };	int sz = sizeof(arr) / sizeof(arr[0]);	my_bubble_sort(arr, sz, sizeof(arr[0]), cmp);	print_arr(arr, sz);	return 0;}

地址統一強轉為char*,以最小字節單位一個字節進行比較和交換,使代碼更具有普適性。

如果需要排序結構體則只需要在前文代碼中主函數里替換my_qsort且把比較函數替換Name_cmp即可。

//1.my_qsort(s, sz, sizeof(s[0]), name_cmp);//2.my_qsort(s, sz, sizeof(s[0]), score_cmp);

?

指針和數組筆試題解析

數組辨析題

注意點。數組名代表整個數組:

  1. sizeof(數組名)
  2. &數組名

除此以外,數組名都是代表首元素地址。

一維數組
int a[] = { 1,2,3,4 };printf("%d/n", sizeof(a));//16printf("%d/n", sizeof(a + 0));//4/8printf("%d/n", sizeof(*a));//4printf("%d/n", sizeof(a + 1));//4/8printf("%d/n", sizeof(a[1]));//4printf("%d/n", sizeof(&a));//4/8printf("%d/n", sizeof(*&a));//16printf("%d/n", sizeof(&a + 1));//4/8printf("%d/n", sizeof(&a[0]));//4/8printf("%d/n", sizeof(&a[0] + 1));//4/8
  1. 只有數組名多帶帶放在sizeof內部才是整個數組。

    a+0放在sizeof內部表示首元素地址+0。

  2. 只要是地址,不管是什么類型的地址大小都是4/8

    基本類型指針,數組指針,函數指針大小都是4/8個字節,故sizeof(&a)=sizeof(int(*)[4])=4sizeof()求指針所占字節而不是解引用訪問權限大小。

  3. *&在一起會抵消。

    sizeof(*&a),&a為整個數組的地址類型int(*)[4],解引用后int[4]大小為16。

字符數組
char arr[] = { "a","b","c","d","e","f" };printf("%d/n", sizeof(arr));//6printf("%d/n", sizeof(arr + 0));//4/8printf("%d/n", sizeof(*arr));//1printf("%d/n", sizeof(arr[1]));//1printf("%d/n", sizeof(&arr));//4/8printf("%d/n", sizeof(&arr + 1));//4/8printf("%d/n", sizeof(&arr[0] + 1));//4/8printf("%d/n", strlen(arr));//隨機值xprintf("%d/n", strlen(arr + 0));//隨機值xprintf("%d/n", strlen(*arr));//報錯printf("%d/n", strlen(arr[1]));//報錯printf("%d/n", strlen(&arr));//隨機值xprintf("%d/n", strlen(&arr + 1));//隨機值x-6printf("%d/n", strlen(&arr[0] + 1));//隨機值x-1
  1. sizeof(*arr)*arr對首元素地址解引用,計算首元素所占空間大小。

    strlen(*arr)*arr依然是首元素,strlen把a也就是97當成地址,訪問到非法內存所以報錯。

2.strlen(&arr)雖然是整個數組的地址,但依然是從首元素開始的,所以strlen依然從第一個元素開始找。

? strlen(&arr+1),先計算&arr+1然后再傳參過去,也就是跳過了整個數組去找。

sizeofstrlen的區別

  • sizeof — 操作符 — 以字節為單位,求變量或類型所創建變量的所占空間的大小

sizoef不是函數,計算類型是必須帶上類型說明符()sizoef內容不參與運算,在編譯期間便轉化完成。

  • strlen — 庫函數 — 求字符串長度即字符個數,遇/0停止。

庫函數,計算字符串長度沒有遇到/0就會一直持續下去。返回類型size_t,參數char* str ,接收的內容都會認為是char*類型的地址。

一個求變量所占空間,一個求字符串大小,二者本身是沒有關系的,但總有人把二者綁在一起“混淆視聽”。

字符串數組

首先明確二者的區別:

//1.字符初始化數組char arr[] = { "a","b","c","d","e","f" };//[a] [b] [c] [d] [e] [f]//2.字符串初始化數組char arr[] = "abcdef";//[a] [b] [c] [d] [e] [f] [/0]

字符初始化數組,存了什么元素數組里就是什么元素。而字符串初始化數組,除了字符串中可見的字符外,還有字符串末尾隱含的/0/0存在于字符串的末尾,是自帶的,雖不算字符串內容,但是字符串中的字符。

char arr[] = "abcdef";printf("%d/n", sizeof(arr));//7printf("%d/n", sizeof(arr + 0));//4/8printf("%d/n", sizeof(*arr));//1printf("%d/n", sizeof(arr[1]));//1printf("%d/n", sizeof(&arr));//4/8printf("%d/n", sizeof(&arr + 1));//4/8printf("%d/n", sizeof(&arr[0] + 1));//4/8printf("%d/n", strlen(arr));//6printf("%d/n", strlen(arr + 0));//6printf("%d/n", strlen(*arr));//報錯printf("%d/n", strlen(arr[1]));//報錯printf("%d/n", strlen(&arr));//6printf("%d/n", strlen(&arr + 1));//隨機值printf("%d/n", strlen(&arr[0] + 1));//5
  1. sizeof計算變量的長度,變量可以是數組,數組元素以及指針。數組就是整個數組的大小,數組元素則是數組元素的大小,指針大小都為4/8。
  2. strlen把傳過來的參數都當作地址,是地址就從該地址處向后遍歷找/0,不是地址當作地址非法訪問就報錯。
常量字符串
char* p = "abcdef";

"abcdef"是常量字符串,用一個字符指針p指向該字符串,實質是p存入了首字符a的地址。由于字符串在內存中連續存放,依此特性便可以遍歷訪問整個字符串。

char* p = "abcdef";
            
                     
             
               

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/119679.html

相關文章

  • C語言進階指針進階

    摘要:本章節在此基礎上,對語言階段指針進行更深層次的研究。數組指針的類型由數組類型決定,先找出數組的類型去掉名就是類型。相當于數組指針所指向數組的數組名。數組指針指向整個數組,將其看作二維數組并解引用得到一行的首元素,從而遍歷訪問。 ...

    浠ラ箍 評論0 收藏0
  • 玩轉指針,手撕c語言——(指針進階

    摘要:函數的返回值為指針就按照字面意思,指針函數的定義顧名思義,指針函數即返回指針的函數。 目錄 前言指針與函數函數的返回值為指針作為函數參數的指針指針函數可以改變變量...

    genedna 評論0 收藏0
  • C語言進階:動態內存管理

    摘要:釋放不完全導致內存泄漏。既然把柔性數組放在動態內存管理一章,可見二者有必然的聯系。包含柔性數組的結構用進行動態內存分配,且分配的內存應大于結構大小,以滿足柔性數組的預期。使用含柔性數組的結構體,需配合以等動態內存分配函數。 ...

    shinezejian 評論0 收藏0
  • 三文讀透指針語法【中篇】@指針進階---函數指針+函數指針數組+指向函數指針數組的指針

    摘要:三文讀透指針上篇本文將繼續介紹有關函數指針的相關內容。在大型工程里,函數指針應用還是挺普遍的。首先看閱讀下面兩段有趣的代碼出自語言陷阱與缺陷看看他們是什么意思代碼代碼函數指針數組函數指針數組,即存放函數指針的數組。 ...

    blastz 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<