欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報(bào)激活碼778899分享:c語言 指針進(jìn)階(三)

柚子快報(bào)激活碼778899分享:c語言 指針進(jìn)階(三)

http://yzkb.51969.com/

嘿嘿,uu們,今天呢我們來剖析指針進(jìn)階的剩下部分,好啦,廢話不多講,開干!

目錄

1:回調(diào)函數(shù)

2:qsort函數(shù)

2.1:void * 指針介紹

2.1.1:代碼1

2.1.2:代碼2

2.2:qsort函數(shù)的使用

2.2.1:代碼1

2.2.2:代碼2

3:冒泡排序模擬實(shí)現(xiàn)qsort函數(shù)

3.1:總代碼(排序整型數(shù)據(jù)--->升序)?

3.2:總代碼(排序結(jié)構(gòu)體數(shù)據(jù)--->按照年齡排序)

3.3:總代碼(排序結(jié)構(gòu)體數(shù)據(jù)---->按照名字排序)

4:sizeof與strlen的對比

4.1:sizeof

4.2:strlen

4.3:sizeof與strlen的對比

5:常見數(shù)組與指針筆試題

5.1:一維數(shù)組

32位平臺

64位平臺

5.2:字符數(shù)組與字符串

5.2.1:字符數(shù)組(sizeof)

32位平臺

64位平臺

5.2.2:字符數(shù)組(strlen)

5.2.3:字符串(sizeof)

32位平臺

64位平臺

5.2.4:字符串(strlen)

5.2.5:指針存儲字符串(sizeof)

32位平臺

64位平臺

5.2.6:指針存儲字符串(strlen)

5.3:二維數(shù)組

32位平臺

64位平臺

6:指針運(yùn)算筆試題

6.1:題目1

6.2:題目2

6.3:題目3

6.4:題目4

6.5:題目5

6.6:題目6

6.7:題目7

6.8:題目8

1:回調(diào)函數(shù)

概念:回調(diào)函數(shù)是指一個(gè)通過函數(shù)指針調(diào)用的函數(shù),如果將函數(shù)的地址作為參數(shù)傳遞給另外一個(gè)函數(shù),當(dāng)這個(gè)指針被用來調(diào)用所指向的函數(shù)時(shí),那么這個(gè)被調(diào)用的函數(shù)就是回調(diào)函數(shù).回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)放直接調(diào)用,而是在特定的事件或條件發(fā)生時(shí)由另外一方調(diào)用的,用于對該事件或條件進(jìn)行響應(yīng).

在之前我們有使用過通過函數(shù)指針來實(shí)現(xiàn)一個(gè)小型計(jì)算器,在那種場景下,我們是將調(diào)用的函數(shù)以參數(shù)的形式傳遞過去,使用函數(shù)指針進(jìn)行接收,函數(shù)指針指向什么函數(shù)就調(diào)用什么函數(shù),這里其實(shí)使用的就是回調(diào)函數(shù).

2:qsort函數(shù)

了解了回調(diào)函數(shù)之后,接下來我們來看一個(gè)使用回調(diào)函數(shù)的例子,qsort函數(shù),qsort函數(shù)是一個(gè)庫函數(shù),底層采用的是快速排序的方式對數(shù)據(jù)進(jìn)行排序,該函數(shù)能夠用來排序任意類型的數(shù)據(jù).對qsort函數(shù)有了基本了解后,接下來我們來看官方的介紹

里面有四個(gè)參數(shù)

(1):void * base------>待排序數(shù)組的首元素地址;

(2):size_t num------->待排序數(shù)組的元素個(gè)數(shù);

(3):size_t size ------->待排序數(shù)組中的一個(gè)元素的大小; ?

//函數(shù)指針,compar指向了一個(gè)函數(shù),該函數(shù)用來比較兩個(gè)元素的大小,e1與e2存放的是兩個(gè)元素的地址

(4):int (*compar) (const void *e1,const void *e2));

uu們可能對上面的void * 這一數(shù)據(jù)類型有些小問題,博主在這里對其簡單補(bǔ)充下.

2.1:void * 指針介紹

void * 是無具體類型的指針.void * 類型的指針能夠存放任意數(shù)據(jù)類型的地址.void *類型的指針不能對其進(jìn)行解引用操作,也不能進(jìn)行 +-整數(shù)的操作.

2.1.1:代碼1

#include

int main()

{

int a = 10;

double b = 1.5;

void* pa = &a;

void* pb = &b;

printf("%p\n", pa);

printf("%p\n", pb);

return 0;

}

2.1.2:代碼2

#include

int main()

{

int a = 10;

double b = 1.5;

void* pa = &a;

void* pb = &b;

pa++;

pb++;

return 0;

}

2.2:qsort函數(shù)的使用

了解了qsort函數(shù)后,接下來我們來看幾段代碼,觀察下qsort函數(shù)的使用.

2.2.1:代碼1

#include

#include

int cmp(const void * e1,const void * e2)

{

return (*(int*)e1) - (*(int*)e2);

}

int main()

{

int arr[10] = { 1,5,6,7,8,9,10,2,3,4 };

int sz = sizeof(arr) / sizeof(arr[0]);

printf("排序前:>");

for (size_t i = 0; i < sz; i++)

{

printf("%d ", arr[i]);

}

printf("\n");

printf("排序后:>");

qsort(arr, sz, sizeof(int), cmp);

for (size_t i = 0; i < sz; i++)

{

printf("%d ", arr[i]);

}

return 0;

}

上面則是通過使用qsort函數(shù)對整型數(shù)據(jù)進(jìn)行排序,是以升序的方式,可能uu們會有如下的疑惑

(1):qsort函數(shù)的第四個(gè)參數(shù)的函數(shù)指針?biāo)赶虻暮瘮?shù)的參數(shù)為什么是const void *

博主將通過一個(gè)小故事來帶著理解下,譬如說有兩個(gè)程序員,一個(gè)是張三,一個(gè)是李四.有一天呢,李四弄了個(gè)榜單但是這個(gè)排行榜還沒有進(jìn)行排序,這個(gè)時(shí)候李四就去找張三幫忙,張三啊,你幫我給這個(gè)榜單進(jìn)行一個(gè)排序吧,這個(gè)時(shí)候張三就問,那你希望我按照什么方式來排序嘞,是按照榜單上的名字還是按照榜單的上編號還是按照榜單上的總成績來排序呢?到這里為止,uu們有沒有發(fā)現(xiàn),張三對榜單的排序是不是有多種方式,而每種排序方式所排序的數(shù)據(jù)類型是不一樣的,這個(gè)時(shí)候我們再回到qsort函數(shù),qsort函數(shù)是C語言的一個(gè)庫函數(shù),開發(fā)者在寫這個(gè)函數(shù)并不知道使用者會按照什么樣的方式去進(jìn)行排序,而void *又能夠存放任意數(shù)據(jù)類型的地址,因此開發(fā)者在編寫的時(shí)候則是使用了void *類型的指針,這樣子使用者在使用的時(shí)候能夠根據(jù)自己想要的排序方式進(jìn)行任意的變化.

(2):函數(shù)指針?biāo)赶虻暮瘮?shù)的返回值為什么是int

? ? ?對于這個(gè)問題,博主將通過官方的文檔來解釋

在官方的文檔中,表示了compar函數(shù)的返回值的意義

(1): > 0:說明p1所指向的元素在 p2所指向的元素的前面;

(2):== 0:說明p1所指向的元素與p2所指向的元素是等價(jià)的;

(3):< 0:說明p1所指向的元素在p2所指向的元素的后面;

解決了上述的疑問后,我們再回到這段代碼

第一個(gè)參數(shù)arr為數(shù)組名,數(shù)組名在一般情況下表示的是首元素地址.

第二個(gè)參數(shù)sz則為待排序數(shù)組的元素個(gè)數(shù)

由于待排序數(shù)組的元素的數(shù)據(jù)類型為整型,因此第三個(gè)參數(shù)為 sizeof(int)即4個(gè)字節(jié)

第四個(gè)參數(shù)是函數(shù)指針,指向的是cmp函數(shù),由于排序的元素都是整型,因此要對其進(jìn)行強(qiáng)制類型轉(zhuǎn)換成 int *,然后再對其解引用計(jì)算其返回值.

在上面我們有了解到,回調(diào)函數(shù)是指一個(gè)通過函數(shù)指針調(diào)用的函數(shù),而cmp函數(shù)則是將其地址作為qsort函數(shù)的參數(shù),因此這里的cmp函數(shù)則是回調(diào)函數(shù)!

2.2.2:代碼2

在上面我們有講到過,qsort函數(shù)能夠排序任意類型的數(shù)據(jù),那么我們再來看下面這段代碼.

#include

#include

#include

int cmp(const void ** e1,const void ** e2)

{

return strcmp((const char*)(*e1),(const char*)(*e2));

}

int main()

{

char* arr[10] = { "ly","wj","duck","gzx","yx","ljh","cj","jwt","lat","hjy"};

int sz = sizeof(arr) / sizeof(arr[0]);

printf("排序前:>");

for (size_t i = 0; i < sz; i++)

{

printf("%s ", arr[i]);

}

printf("\n");

qsort(arr, sz, sizeof(arr[0]), cmp);

printf("排序后:>");

for (size_t i = 0; i < sz; i++)

{

printf("%s ", arr[i]);

}

return 0;

}

上面這段代碼呢,則是通過qsort函數(shù)實(shí)現(xiàn)了對字符串的排序,可能uu們在想字符串怎么能夠?qū)ζ溥M(jìn)行排序呢?博主將帶著uu們一步一步地剖析.

(1):qsort函數(shù)的第四個(gè)參數(shù)cmp函數(shù)的兩個(gè)參數(shù)為什么是const void **類型

在函數(shù)那一章節(jié)我們有講到過,函數(shù)在傳值傳參時(shí),形參是實(shí)參的一份臨時(shí)拷貝,改變形參不會改變實(shí)參,而數(shù)組中的每個(gè)元素的元素類型都是char * 類型的,那么要令實(shí)參能夠發(fā)生變化,則需要傳址傳參,因此這里使用 const void ** 來存儲一級指針的地址.

(2):strcmp函數(shù)

uu們應(yīng)該發(fā)現(xiàn)了,博主在cmp函數(shù)那里使用了strcmp函數(shù),這是C語言的一個(gè)庫函數(shù),用于比較字符串的大小的,并且在使用的時(shí)候需要包含這個(gè)頭文件.

strcmp函數(shù)是字符串比較函數(shù),它會比較兩個(gè)字符串的大小,是通過比較字符串中的每一個(gè)字符的ascii碼值,譬如:若 str1中的第一個(gè)字符與str2中的第一個(gè)字符相等則繼續(xù)向后比較,直到遇到第一個(gè)不匹配的字符或者比較結(jié)束.當(dāng)返回值?>? 0:說明 str1 中 第一個(gè)不匹配的字符大于str2中第一個(gè)不匹配的字符.當(dāng)返回值 ==0:說明 str1 中 的每一個(gè)與str2中的每一個(gè)字符都相等.當(dāng)返回值

(3):由于strcmp函數(shù)的參數(shù)類型都是const char *,而在傳參時(shí)是通過傳址傳參,因此首先對二級指針 void ** 解引用得到一級指針 void *,接著再對其進(jìn)行強(qiáng)制類型轉(zhuǎn)換.

3:冒泡排序模擬實(shí)現(xiàn)qsort函數(shù)

在數(shù)組那一章節(jié),博主講了一個(gè)冒泡排序,冒泡排序的核心是:兩兩互相比較然后進(jìn)行交換.這里博主就不再細(xì)講啦,忘了uu可以去看看博主的數(shù)組那一篇博客哦!

#define _CRT_SECURE_NO_WARNINGS

#include

int main()

{

int arr[10] = { 1,3,2,5,6,7,8,9,10,4 };

//求出數(shù)組中的元素個(gè)數(shù)

int sz = sizeof(arr) / sizeof(arr[0]);

printf("排序前:>");

for (int i = 0; i < sz; i++)

{

printf("%d ", arr[i]);

}

//確定總趟數(shù)

for (int i = 0; i < sz - 1; i++)

{

//每進(jìn)行一次冒泡排序,趟數(shù)要減少,因此- 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;

}

}

}

printf("\n");

printf("排序后:>");

for (int i = 0; i < sz; i++)

{

printf("%d ", arr[i]);

}

return 0;

}

以上呢就是我們之前實(shí)現(xiàn)冒泡排序的代碼,那么現(xiàn)在博主將使用冒泡排序來模擬實(shí)現(xiàn)qsort函數(shù).首先是參數(shù)部分,qsort函數(shù)有4個(gè)參數(shù)

(1):第一個(gè)參數(shù)是待排序的數(shù)組的首元素地址.

(2):數(shù)組的元素的個(gè)數(shù).

(3):數(shù)組的每一個(gè)元素的所占的內(nèi)存空間的大小.

(4):一個(gè)函數(shù)指針,用來比較元素的大小的.

那么我們冒泡排序的參數(shù)應(yīng)該如下面所示

void Bubble_sort(void * base,size_t num,size_t size,int(*compare)(const void * e1,const void * e2));

?PS:由于不確定數(shù)組的元素是什么類型的,那么我們就用void *指針來封裝這個(gè)首元素地址.

然后接下來我們再來看還有哪些部分要變化,首先能夠確定的是,兩個(gè)for循環(huán)是不需要變化,因?yàn)槊芭菖判虻谋举|(zhì)是兩兩互相交換.

那么接下來看循環(huán)的判斷部分

由于此時(shí)第一個(gè)參數(shù)是void *,那么我們則不能用[]的方式去獲取元素了,那么有什么辦法呢?在指針初階那一階段,博主有講到過,指針的類型決定了其在解引用以及+-整數(shù)的時(shí)候跳過幾個(gè)字節(jié).那么首先不確定要排序的數(shù)據(jù)類型是什么,但是有這個(gè)數(shù)據(jù)元素的所占的內(nèi)存空間大小,并且也有待排序的數(shù)組的元素個(gè)數(shù).那么我們是不是可以用char *指針來進(jìn)行訪問呢,因?yàn)閏har * 指針每次 +-1都是跳過一個(gè)字節(jié),然后我又有了這個(gè)元素的所占的內(nèi)存空間的大小,并且又有這個(gè)cmp函數(shù)可以來比較大小,那么就能很輕易地去改寫if的判斷條件.

void Bubble_sort(void * base,size_t num,size_t size,int(*compare)(const void * e1,const void * e2))

{

for (int i = 0; i < num; i++)

{

for (int j = 0; j < num - i - 1; j++)

{

if (compare((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

{

;

}

}

}

}

判斷是否符合交換條件 由于不確定要排序的數(shù)據(jù)類型,因此使用字符指針,因?yàn)樽址羔樏?1是跳過一個(gè)字節(jié) 當(dāng)確定比較的數(shù)據(jù)元素的類型,由于冒泡排序的核心是兩兩互相比較 ?那么此時(shí)通過初始地址base + j * size(數(shù)據(jù)類型的大小)得到第一個(gè)元素的地址 ?然后通過base + (j + 1) * size得到第二個(gè)比較元素的地址

然后接下來就是交換部分了,由于我不確定我要交換的數(shù)據(jù)類型,那么此時(shí)我同樣可以使用char *指針,這個(gè)時(shí)候就是一個(gè)字節(jié)一個(gè)字節(jié)地進(jìn)行交換,并且需要傳第三個(gè)參數(shù),每一個(gè)元素所占的內(nèi)存空間的大小.那么此時(shí)交換函數(shù)swap如下

void swap(char* buf1, char* buf2, size_t size)

{

int i = 0;

for (i = 0; i < size; i++)

{

char tmp = *buf1;

*buf1 = *buf2;

*buf2 = tmp;

buf1++;

buf2++;

}

}

void bubble_sort(void* base, size_t num, size_t size, int (*compare)(const void* e1, const void* e2))

{

int i = 0;

int j = 0;

//確定冒泡排序的趟數(shù)

for (i = 0; i < num - 1; i++)

{

for (j = 0; j < num - 1 - i; j++)

{

//判斷是否符合交換條件

/*

* 由于不確定要排序的數(shù)據(jù)類型,因此使用字符指針,因?yàn)樽址羔樏?1是跳過一個(gè)字節(jié)

* 當(dāng)確定比較的數(shù)據(jù)元素的類型,由于冒泡排序的核心是兩兩互相比較

* 那么此時(shí)通過初始地址base + j * size(數(shù)據(jù)類型的大小)得到第一個(gè)元素的地址

* 然后通過base + (j + 1) * size得到第二個(gè)比較元素的地址

*/

if (compare((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

{

//調(diào)用交換函數(shù)進(jìn)行交換

swap((char*)base + j * size, (char*)base + (j + 1) * size, size);

}

}

}

}

3.1:總代碼(排序整型數(shù)據(jù)--->升序)

#define _CRT_SECURE_NO_WARNINGS

#include

#include

#include

int cmp(const void * e1,const void * e2)

{

return *(int*)e1 - *(int*)e2;

}

void swap(char* e1,char*e2,size_t size)

{

for (size_t i = 0; i < size; i++)

{

char temp = *e1;

*e1 = *e2;

*e2 = temp;

e1++;

e2++;

}

}

void Bubble_sort(void * base,size_t num,size_t size,int(*compare)(const void * e1,const void * e2))

{

for (int i = 0; i < num; i++)

{

for (int j = 0; j < num - i - 1; j++)

{

if (compare((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

{

swap((char*)base + j * size, (char*)base + (j + 1) * size, size);

}

}

}

}

//

int main()

{

int arr[10] = { 1,3,2,5,6,7,8,9,10,4};

size_t sz = sizeof(arr) / sizeof(arr[0]);

Bubble_sort(arr, sz,sizeof(arr[0]),cmp);

for(int i = 0; i < sz; i++)

{

printf("%d ", arr[i]);

}

return 0;

}

3.2:總代碼(排序結(jié)構(gòu)體數(shù)據(jù)--->按照年齡排序)

#include

#include

#include

typedef struct Person

{

char name[20];

int age;

}Person;

int cmp(const void * e1,const void * e2)

{

return ((struct Person *)e1)->age - ((struct Person *)e2)->age;

}

void swap(char* e1,char*e2,size_t size)

{

for (size_t i = 0; i < size; i++)

{

char temp = *e1;

*e1 = *e2;

*e2 = temp;

e1++;

e2++;

}

}

void Bubble_sort(void * base,size_t num,size_t size,int(*compare)(const void * e1,const void * e2))

{

for (int i = 0; i < num; i++)

{

for (int j = 0; j < num - i - 1; j++)

{

if (compare((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

{

swap((char*)base + j * size, (char*)base + (j + 1) * size, size);

}

}

}

}

//

int main()

{

Person arr[4] = { {"張三",20},{"李四",21},{"王五",15},{"小明",6} };

int sz = sizeof(arr) / sizeof(arr[0]);

printf("排序前:>");

for (int i = 0; i < sz; i++)

{

printf("%s:>%d ", arr[i].name, arr[i].age);

}

printf("\n");

Bubble_sort(arr, sz,sizeof(arr[0]),cmp);

printf("排序后:>");

for(int i = 0; i < sz; i++)

{

printf("%s:>%d ", arr[i].name,arr[i].age);

}

return 0;

}

3.3:總代碼(排序結(jié)構(gòu)體數(shù)據(jù)---->按照名字排序)

#define _CRT_SECURE_NO_WARNINGS

#include

#include

#include

typedef struct Person

{

char name[20];

int age;

}Person;

int cmp(const void * e1,const void * e2)

{

return strcmp(((struct Person *)e1)->name,((struct Person *)e2)->name);

}

void swap(char* e1,char*e2,size_t size)

{

for (size_t i = 0; i < size; i++)

{

char temp = *e1;

*e1 = *e2;

*e2 = temp;

e1++;

e2++;

}

}

void Bubble_sort(void * base,size_t num,size_t size,int(*compare)(const void * e1,const void * e2))

{

for (int i = 0; i < num; i++)

{

for (int j = 0; j < num - i - 1; j++)

{

if (compare((char*)base + j * size, (char*)base + (j + 1) * size) > 0)

{

swap((char*)base + j * size, (char*)base + (j + 1) * size, size);

}

}

}

}

//

int main()

{

Person arr[4] = { {"張三",20},{"李四",21},{"王五",15},{"小明",6} };

int sz = sizeof(arr) / sizeof(arr[0]);

printf("排序前:>");

for (int i = 0; i < sz; i++)

{

printf("%s:>%d ", arr[i].name, arr[i].age);

}

printf("\n");

Bubble_sort(arr, sz,sizeof(arr[0]),cmp);

printf("排序后:>");

for(int i = 0; i < sz; i++)

{

printf("%s:>%d ", arr[i].name,arr[i].age);

}

return 0;

}

4:sizeof與strlen的對比

4.1:sizeof

在操作符那一章節(jié),我們學(xué)習(xí)過sizeof操作符,sizeof計(jì)算的是變量所占據(jù)的內(nèi)存空間的大小,單位是字節(jié),若操作數(shù)為數(shù)據(jù)類型的話,則計(jì)算的是該數(shù)據(jù)類型在空間中所占的大小.

PS:sizeof只關(guān)注所占據(jù)的內(nèi)存空間的大小,不在乎內(nèi)存中所占據(jù)的數(shù)據(jù).

#define _CRT_SECURE_NO_WARNINGS

#include

int main()

{

int a = 0;

double b = 0.0;

float c = 0.0f;

printf("變量a所占據(jù)的內(nèi)存空間大小為:>%zd\n", sizeof(a));

printf("變量b所占據(jù)的內(nèi)存空間大小為:>%zd\n", sizeof(b));

printf("變量c所占據(jù)的內(nèi)存空間大小為:>%zd\n", sizeof(c));

return 0;

}

4.2:strlen

strlen是C語言的一個(gè)庫函數(shù),用于求取字符串的長度,其原型如下:

strlen函數(shù)統(tǒng)計(jì)的是從參數(shù)str向后,\0之前的字符個(gè)數(shù),因?yàn)橹拔覀儗W(xué)習(xí)過字符串的結(jié)束標(biāo)志是\0.

PS:strlen函數(shù)會一直向后\0,直到找到為止,因此在使用時(shí)可能會存在越界的檢查.我們來看下面這段代碼

#define _CRT_SECURE_NO_WARNINGS

#include

int main()

{

char arr[] = { 'a','b','c','d' };

char str[] = "abcd";

printf("%d\n", sizeof(arr));

printf("%d\n", sizeof(str));

printf("\n");

printf("%d\n", strlen(arr));

printf("%d\n", strlen(str));

return 0;

}

(1)首先sizeof(arr)求的是arr數(shù)組在整個(gè)內(nèi)存空間所占據(jù)的大小,在數(shù)組那一章節(jié)博主有講到過,數(shù)組名一般情況下表示的是首元素地址,但是有兩種特殊情況表示的是整個(gè)數(shù)組

sizeof(數(shù)組名),計(jì)算的是整個(gè)數(shù)組的大小算的是整個(gè)數(shù)組的大小,sizeof內(nèi)部單獨(dú)放一個(gè)數(shù)組名,數(shù)組名表示整個(gè)數(shù)組。&數(shù)組名,取出的是整個(gè)數(shù)組的地址。&數(shù)組名,數(shù)組名表示整個(gè)數(shù)組

而arr數(shù)組里頭有4個(gè)字符變量,一個(gè)字符變量所占據(jù)的內(nèi)存空間大小為1個(gè)字節(jié)因此sizeof(arr)的結(jié)果為4.

(2):有的uu根據(jù)第一個(gè)解釋就在想,按照上面這種解釋的方法的話,那么sizeof(str)應(yīng)該也是4啊,這個(gè)5是怎么來的呢?uu們這里要注意,arr是字符數(shù)組,str是字符串,字符串有一個(gè)特性,其結(jié)束標(biāo)志是\0,因此str中還有一個(gè)\0字符,所以這里sizeof(str)的結(jié)果是5.

我們可以通過監(jiān)視窗口觀察arr與str中所存儲的內(nèi)容.

很明顯,字符串str比字符數(shù)組arr多了\0字符.

(3):由于字符串str中的\0字符有4個(gè)字符,因此strlen(str)的結(jié)果為4,這里相信uu們沒有什么問題.

(4):在上面博主有講到過strlen統(tǒng)計(jì)的是\0之前的字符個(gè)數(shù),如果沒有找到\0字符,則會一直向后找,直到找到為止,很明顯字符數(shù)組arr中有4個(gè)字符,但是沒有\(zhòng)0字符,因此strlen函數(shù)在求其長度的時(shí)候會一直向后找,找到\0,這個(gè)時(shí)候求出來的值是隨機(jī)值,具體是多少要看編譯器了,博主求出來的結(jié)果是15.如果uu們多運(yùn)行幾次這段代碼的話,會發(fā)現(xiàn)求出來的值是不一樣滴,這里博主就不多次運(yùn)行啦!

4.3:sizeof與strlen的對比

sizeof

sizeof是操作符.sizeof計(jì)算操作數(shù)的類型在內(nèi)存空間中所占據(jù)的空間大小,單位是字節(jié).不關(guān)注內(nèi)存中存放的數(shù)據(jù).

strlen

strlen是庫函數(shù),使用時(shí)需要包含頭文件.strlen是計(jì)算字符串?度的,統(tǒng)計(jì)的是 \0 之前的字符個(gè)數(shù).strlen會關(guān)注內(nèi)存中是否有 \0 ,如果沒有 \0 字符,則會持續(xù)往后找,因此會存在越界的可能性.

5:常見數(shù)組與指針筆試題

熟悉了sizeof與strlen的區(qū)別后,接下來我們來看一些常見的筆試題.uu們可以自己先做一下哦~

5.1:一維數(shù)組

#include

int main()

{

int arr[] = { 1,2,3,4 };

printf("%d\n", sizeof(arr));

printf("%d\n", sizeof(arr + 0));

printf("%d\n", sizeof(*arr));

printf("%d\n", sizeof(arr + 1));

printf("%d\n", sizeof(arr[1]));

printf("%d\n", sizeof(&arr));

printf("%d\n", sizeof(*&arr));

printf("%d\n", sizeof(&arr + 1));

printf("%d\n", sizeof(&arr[0]));

printf("%d\n", sizeof(&arr[0] + 1));

return 0;

}

(1):在數(shù)組階段,我們講到過,數(shù)組名在一般情況下表示的是首元素地址,但是存在兩種特例

sizeof(數(shù)組名),計(jì)算的是整個(gè)數(shù)組的大小算的是整個(gè)數(shù)組的大小,sizeof內(nèi)部單獨(dú)放一個(gè)數(shù)組名,數(shù)組名表示整個(gè)數(shù)組.&數(shù)組名,取出的是整個(gè)數(shù)組的地址。&數(shù)組名,數(shù)組名表示整個(gè)數(shù)組名

因此,這里sizeof(arr)計(jì)算的是整個(gè)數(shù)組的大小,1個(gè)整型所占據(jù)的內(nèi)存空間大小為4個(gè)字節(jié),而arr數(shù)組里頭有4個(gè)整型,因此sizeof(arr)的結(jié)果是16.

(2):與第1種情況相比,第2個(gè)多了個(gè) +0,我們說數(shù)組名表示的是首元素地址,+ 0之后則依舊是首元素地址,這里有個(gè)小細(xì)節(jié)不知道uu們有沒有觀察到,sizeof(數(shù)組名)這里,數(shù)組名只能夠單獨(dú)出現(xiàn),不能夠有其他表達(dá)式,否則表示則不是整個(gè)數(shù)組.所以,sizeof(arr + 0)這里計(jì)算的則是地址的大小,地址的大小在指針初階我們有學(xué)習(xí)到,要取決于平臺,32位平臺下地址的大小為4,64位平臺下地址的大小為8,因此,這里的sizeof(arr + 0)的結(jié)果為 4 或者 8.

(3):數(shù)組名表示的是首元素地址,這里對其解引用得到的是第1個(gè)元素,因此這里sizeof(*arr)計(jì)算的是arr數(shù)組中第1個(gè)元素 1 所占據(jù)的內(nèi)存空間,1為整型數(shù)據(jù),占據(jù)4個(gè)字節(jié),因此這里的結(jié)果是4

(4):數(shù)組名表示的是首元素地址,地址 + 1以后還是地址,因此這里的sizeof(arr + 1)計(jì)算的是地址所占據(jù)的內(nèi)存空間的大小,所以這里的結(jié)果為 4 或者 8.

(5):arr[1]表示通過下標(biāo)訪問數(shù)組中的第二個(gè)元素,因此這里的sizoef(arr[1])計(jì)算的是數(shù)組中的第2個(gè)元素所占據(jù)的內(nèi)存空間的大小,所以這里的結(jié)果為 4.

(6)這一題很多uu會掉坑,很多uu的結(jié)果會這么想:&數(shù)組名,取出的是整個(gè)數(shù)組的地址.所以這里的結(jié)果是16.如果這么想的話就大錯(cuò)特錯(cuò)啦,雖然&數(shù)組名,取出的是整個(gè)數(shù)組的地址,但是,數(shù)組的地址也是地址呀,因此這里依舊計(jì)算的是地址所占據(jù)的內(nèi)存空間的大小,所以這sizeof(&arr)的結(jié)果是 4 或者 8.

?

(7):這里首先&arr,取出的是整個(gè)數(shù)組的地址,得到數(shù)組的地址后,再對其解引用,這樣子的話,得到的就是整個(gè)數(shù)組,因此這里sizeof(*&arr)計(jì)算的是整個(gè)數(shù)組的大小,所以結(jié)果為16.

uu們還可以這樣子去理解,這里的解引用操作符 *與 取地址操作符 &相抵消了,那么剩下來的則是sizeof(arr)等價(jià)于sizeof(數(shù)組名),計(jì)算的是整個(gè)數(shù)組的大小.

?

(8):這里首先&arr,取出的是整個(gè)數(shù)組的地址,接著對地址 + 1,地址 + 1以后還是地址,因此這里的sizeof(&arr + 1)計(jì)算的是地址所占據(jù)的內(nèi)存空間的大小,所以這里的結(jié)果為 4 或者 8.?

?

(9):由于[]操作符的優(yōu)先級高于&,因此arr首先與[]結(jié)合,這里則是通過下標(biāo)訪問拿到首元素 1,然后再通過取地址符號該元素的地址,因此sizeof(&arr[0])計(jì)算的是首元素的地址所占據(jù)的內(nèi)存空間的大小,因此結(jié)果為 4 / 8.

?

(10):由于[]操作符的優(yōu)先級高于&,因此arr首先與[]結(jié)合,這里則是通過下標(biāo)訪問首元素 1,然后再通過取地址符號該元素的地址,接下來再對地址 + 1,地址 +1以后依舊是地址并且這里得到的地址是第2個(gè)元素的地址(這里不明白為什么是第二個(gè)元素的地址的uu可以再去看看博主指針初階那篇博客哦),因此這里的sizeof(&arr[0] + 1)計(jì)算的是地址的大小,結(jié)果為 4 或者 8.

32位平臺

64位平臺

5.2:字符數(shù)組與字符串

5.2.1:字符數(shù)組(sizeof)

int main()

{

char arr[] = { 'a','b','c','d','e' };

printf("%d\n", sizeof(arr));

printf("%d\n", sizeof(arr + 0));

printf("%d\n", sizeof(*arr));

printf("%d\n", sizeof(arr[1]));

printf("%d\n", sizeof(&arr));

printf("%d\n", sizeof(&arr + 1));

printf("%d\n", sizeof(&arr[0] + 1));

return 0;

}

(1):這里的sizeof(arr)屬于兩種情況之一,因此這里計(jì)算的是整個(gè)數(shù)組的大小,1個(gè)字符型數(shù)據(jù)在內(nèi)存空間中占據(jù)1個(gè)字節(jié),而arr數(shù)組中有5個(gè)字符型數(shù)據(jù),因此這里的結(jié)果為 5.

(2):數(shù)組名表示的是首元素地址,+ 0之后則依舊是首元素地址,所以,sizeof(arr + 0)這里計(jì)算的則是地址的大小,因此,這里的sizeof(arr + 0)的結(jié)果為 4 或者 8.

(3):數(shù)組名表示的是首元素地址,這里對其解引用得到的是第1個(gè)元素,因此這里sizeof(*arr)計(jì)算的是arr數(shù)組中第1個(gè)元素 'a'?所占據(jù)的內(nèi)存空間,'a'為字符型數(shù)據(jù),占據(jù)1個(gè)字節(jié),因此這里的結(jié)果是1.

(4):arr[1]表示通過下標(biāo)訪問數(shù)組中的第2個(gè)元素,因此這里的sizoef(arr[1])計(jì)算的是數(shù)組中的第2個(gè)元素所占據(jù)的內(nèi)存空間的大小,所以這里的結(jié)果為 1.

(5)&數(shù)組名,取出的是整個(gè)數(shù)組的地址.數(shù)組的地址也是地址,因此這里依舊計(jì)算的是地址所占據(jù)的內(nèi)存空間的大小,所以這sizeof(&arr)的結(jié)果是 4 或者 8.

(6):這里首先&arr,取出的是整個(gè)數(shù)組的地址,接著對地址 + 1,地址 + 1以后還是地址,因此這里的sizeof(&arr + 1)計(jì)算的是地址所占據(jù)的內(nèi)存空間的大小,所以這里的結(jié)果為 4 或者 8.?

(7):由于[]操作符的優(yōu)先級高于&,因此arr首先與[]結(jié)合,這里則是通過下標(biāo)訪問首元素 'a',然后再通過取地址符號該元素的地址,接下來再對地址 + 1,地址 +1以后依舊是地址并且這里得到的地址是第2個(gè)元素的地址,因此這里的sizeof(&arr[0] + 1)計(jì)算的是地址的大小,結(jié)果為 4 或者 8.

32位平臺

64位平臺

5.2.2:字符數(shù)組(strlen)

int main()

{

char arr[] = { 'a','b','c','d','e' };

printf("%d\n", strlen(arr));

printf("%d\n", strlen(arr + 0));

printf("%d\n", strlen(*arr));

printf("%d\n", strlen(arr[1]));

printf("%d\n", strlen(&arr));

printf("%d\n", strlen(&arr + 1));

printf("%d\n", strlen(&arr[0] + 1));

return 0;

}

在上面博主有講到過,strlen函數(shù)統(tǒng)計(jì)的是\0之前的字符個(gè)數(shù),如果沒有遇到\0,則會繼續(xù)向后找,直到遇到\0,因此有存在越界的可能性.

(1):arr為數(shù)組名,在一般情況下表示的是首元素地址,因此這里的strlen(arr)是從字符'a'開始統(tǒng)計(jì),直到遇到\0為止,我們仔細(xì)觀察看這個(gè)字符數(shù)組,發(fā)現(xiàn)里面沒有'\0',因此在統(tǒng)計(jì)的時(shí)候,會發(fā)生越界的情況,所以這里的結(jié)果則是隨機(jī)值.

(2):arr為數(shù)組名,表示的是首元素地址,+ 0之后依舊表示的是地址且是首元素地址,因此這里的strlen(arr)是從字符'a'開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符數(shù)組arr里面沒有'\0',因此在統(tǒng)計(jì)的時(shí)候,會發(fā)生越界的情況,所以這里的結(jié)果則是隨機(jī)值.

(3):arr為數(shù)組名,表示的是首元素地址,對其解引用后得到首元素字符'a',在前面的時(shí)候,我們知道字符型是整型家族中的一種,字符型數(shù)據(jù)在內(nèi)存中是以ascii碼存儲的,'a'的ascii碼為97,從地址的角度出發(fā),相當(dāng)于使用strlen函數(shù)去訪問97那一塊地址空間,可是97那塊空間并不是數(shù)組arr的空間,所以發(fā)生了空間的非法訪問,因此這里的結(jié)果是錯(cuò)誤的.

(4):arr[1]表示通過下標(biāo)訪問數(shù)組中的第2個(gè)元素'b','b'的ascii碼為98,從地址的角度出發(fā),相當(dāng)于使用strlen函數(shù)去訪問98那一塊地址空間,由于98那塊空間并不是數(shù)組arr的空間,所以發(fā)生了空間的非法訪問,因此這里的結(jié)果是錯(cuò)誤的.

(5):&arr表示取出的是數(shù)組的地址,uu們?nèi)绻€記得的話,在數(shù)組那一章節(jié),博主有講到過,數(shù)組的地址與首元素的地址是一樣的,因此這里的strlen(&arr)是從字符'a'開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符數(shù)組arr里面沒有'\0',因此在統(tǒng)計(jì)的時(shí)候,會發(fā)生越界的情況,所以這里的結(jié)果則是隨機(jī)值.

(6):&arr表示取出的是數(shù)組的地址,數(shù)組的地址 + 1跳過的大小是整個(gè)數(shù)組的大小,因此這里是strlen(&arr + 1)是從 'e'的下一個(gè)位置開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符數(shù)組arr里面沒有'\0',因此在統(tǒng)計(jì)的時(shí)候,會發(fā)生越界的情況,所以這里的結(jié)果則是隨機(jī)值.

(7)::由于[]操作符的優(yōu)先級高于&,因此arr首先與[]結(jié)合,這里則是通過下標(biāo)訪問首元素 'a',然后再通過取地址符號該元素的地址,接下來再對地址 + 1,地址 +1以后依舊是地址并且這里得到的地址是第2個(gè)元素的地址即 'b'的地址,因此這里是strlen(&arr[0]?+ 1)是從 'b'的位置開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符數(shù)組arr里面沒有'\0',因此在統(tǒng)計(jì)的時(shí)候,會發(fā)生越界的情況,所以這里的結(jié)果則是隨機(jī)值.

5.2.3:字符串(sizeof)

int main()

{

char arr[] = "abcdef";

printf("%d\n", sizeof(arr));

printf("%d\n", sizeof(arr + 0));

printf("%d\n", sizeof(*arr));

printf("%d\n", sizeof(arr[1]));

printf("%d\n", sizeof(&arr));

printf("%d\n", sizeof(&arr + 1));

printf("%d\n", sizeof(&arr[0] + 1));

return 0;

}

在前面的章節(jié)博主有講到過,字符串的結(jié)束標(biāo)志是'\0'并且字符串也是能夠存儲在字符數(shù)組里頭的,并且在存儲的時(shí)候存儲的是首字符的地址.

(1):arr為數(shù)組名,并且是單獨(dú)出現(xiàn),因此這里的sizeof(arr)求的是整個(gè)數(shù)組所占的內(nèi)存空間大小,由于字符串的結(jié)束標(biāo)志是'\0',因此在計(jì)算的時(shí)候要帶上'\0'字符,所以結(jié)果是 7.

?

(2):數(shù)組名表示的是首元素地址,+ 0之后則依舊是首元素地址,所以,sizeof(arr + 0)這里計(jì)算的則是地址的大小,因此,這里的sizeof(arr + 0)的結(jié)果為 4 或者 8.

?

(3):數(shù)組名表示的是首元素地址,這里對其解引用得到的是第1個(gè)元素,因此這里sizeof(*arr)計(jì)算的是arr數(shù)組中第1個(gè)元素 'a'?所占據(jù)的內(nèi)存空間,'a'為字符型數(shù)據(jù),占據(jù)1個(gè)字節(jié),因此這里的結(jié)果是1.

(4):arr[1]表示通過下標(biāo)訪問數(shù)組中的第2個(gè)元素,因此這里的sizoef(arr[1])計(jì)算的是數(shù)組中的第2個(gè)元素所占據(jù)的內(nèi)存空間的大小,所以這里的結(jié)果為 1.

?

(5)&數(shù)組名,取出的是整個(gè)數(shù)組的地址.數(shù)組的地址也是地址,因此這里依舊計(jì)算的是地址所占據(jù)的內(nèi)存空間的大小,所以這sizeof(&arr)的結(jié)果是 4 或者 8.

(6):這里首先&arr,取出的是整個(gè)數(shù)組的地址,接著對地址 + 1,地址 + 1以后還是地址,因此這里的sizeof(&arr + 1)計(jì)算的是地址所占據(jù)的內(nèi)存空間的大小,所以這里的結(jié)果為 4 或者 8.?

(7):由于[]操作符的優(yōu)先級高于&,因此arr首先與[]結(jié)合,這里則是通過下標(biāo)訪問首元素 'a',然后再通過取地址符號該元素的地址,接下來再對地址 + 1,地址 +1以后依舊是地址并且這里得到的地址是第2個(gè)元素的地址,因此這里的sizeof(&arr[0] + 1)計(jì)算的是地址的大小,結(jié)果為 4 或者 8.

32位平臺

64位平臺

5.2.4:字符串(strlen)

int main()

{

char arr[] = "abcdef";

printf("%d\n", strlen(arr));

printf("%d\n", strlen(arr + 0));

printf("%d\n", strlen(*arr));

printf("%d\n", strlen(arr[1]));

printf("%d\n", strlen(&arr));

printf("%d\n", strlen(&arr + 1));

printf("%d\n", strlen(&arr[0] + 1));

return 0;

}

(1):arr為數(shù)組名,在一般情況下表示的是首元素地址,因此這里的strlen(arr)是從字符'a'開始統(tǒng)計(jì),直到遇到\0為止,由于字符串的結(jié)束標(biāo)志是'\0',所以這里的結(jié)果則是6.

(2):arr為數(shù)組名,表示的是首元素地址,+ 0之后依舊表示的是地址且是首元素地址,因此這里的strlen(arr)是從字符'a'開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符串的結(jié)束標(biāo)志是'\0',所以這里的結(jié)果則是6.?

(3):arr為數(shù)組名,表示的是首元素地址,對其解引用后得到首元素字符'a',在前面的時(shí)候,我們知道字符型是整型家族中的一種,字符型數(shù)據(jù)在內(nèi)存中是以ascii碼存儲的,'a'的ascii碼為97,從地址的角度出發(fā),相當(dāng)于使用strlen函數(shù)去訪問97那一塊地址空間,可是97那塊空間并不是數(shù)組arr的空間,所以發(fā)生了空間的非法訪問,因此這里的結(jié)果是錯(cuò)誤的.

(4):arr[1]表示通過下標(biāo)訪問字符串中的第2個(gè)元素'b','b'的ascii碼為98,從地址的角度出發(fā),相當(dāng)于使用strlen函數(shù)去訪問98那一塊地址空間,由于98那塊空間并不是數(shù)組arr的空間,所以發(fā)生了空間的非法訪問,因此這里的結(jié)果是錯(cuò)誤的.

?

(5):&arr表示取出的是數(shù)組的地址,uu們?nèi)绻€記得的話,在數(shù)組那一章節(jié),博主有講到過,數(shù)組的地址與首元素的地址是一樣的,因此這里的strlen(&arr)是從字符'a'開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符串的結(jié)束標(biāo)志是'\0',所以這里的結(jié)果則是6.

(6):&arr表示取出的是數(shù)組的地址,數(shù)組的地址 + 1跳過的大小是整個(gè)數(shù)組的大小,因此這里是strlen(&arr + 1)是從 '\0’字符的下一個(gè)位置開始統(tǒng)計(jì),直到遇到'\0'為止,所以這里的結(jié)果則是隨機(jī)值.

(7)::由于[]操作符的優(yōu)先級高于&,因此arr首先與[]結(jié)合,這里則是通過下標(biāo)訪問首元素 'a',然后再通過取地址符號該元素的地址,接下來再對地址 + 1,地址 +1以后依舊是地址并且這里得到的地址是第2個(gè)元素的地址即 'b'的地址,因此這里是strlen(&arr[0]?+ 1)是從 'b'的位置開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符串的結(jié)束標(biāo)志是'\0',所以這里的結(jié)果則是?5.

5.2.5:指針存儲字符串(sizeof)

?在指針進(jìn)階(一)博主有講到過,字符串能夠存儲在指針變量中,這個(gè)指針變量存儲的是首元素的地址.

int main()

{

char* p = "abcdef";

printf("%d\n", sizeof(p));

printf("%d\n", sizeof(p + 1));

printf("%d\n", sizeof(*p));

printf("%d\n", sizeof(p[0]));

printf("%d\n", sizeof(&p));

printf("%d\n", sizeof(&p + 1));

printf("%d\n", sizeof(&p[0] + 1));

return 0;

}

(1):p是個(gè)指針變量,指針存儲的是地址,因此sizeof(p)計(jì)算的則是地址所占據(jù)的內(nèi)存空間的大小,所以結(jié)果為?4 或者 8;

(2):p是個(gè)指針變量,在指針初階博主有講到過,指針+-整數(shù)會所跳過幾個(gè)字節(jié)取決于該指針的類型,這里是字符指針,因此 + 1跳過一個(gè)字節(jié),p + 1以后跳過一個(gè)字節(jié)即指向字符'b'的地址,因此這里的sizeof(p + 1)計(jì)算的依舊是地址所占據(jù)的內(nèi)存空間的大小,所以結(jié)果為 4 或者 8;

?

(3):指針變量p存儲的是字符串中'a'的地址,對其解引用得到字符'a',因此sizeof(*p)計(jì)算的則是字符'a'所占據(jù)的內(nèi)存空間的大小,所以結(jié)果為 1;?

?

(4):p[0] 等價(jià)于 *(p + 0),因此這里計(jì)算的依舊是字符'a'所占據(jù)的內(nèi)存空間的大小,所以結(jié)果為 1;??

(5):&p得到的是指針變量p的地址,指針的地址也是地址,因此這里的sizeof(&p)計(jì)算的依舊是地址所占據(jù)的內(nèi)存空間的大小,所以結(jié)果為 4 或者 8;?

?

(6):&p得到的是指針變量p的地址,地址 + 1依舊是地址,因此這里的sizeof(&p + 1)計(jì)算的依舊是地址所占據(jù)的內(nèi)存空間的大小,所以結(jié)果為 4 或者 8;??

?

(7):p[0] 等價(jià)于 *(p + 0),然后對其取地址得到的是字符變量'a'的地址,,地址 + 1依舊是地址,因此這里的sizeof(&p[0] + 1)計(jì)算的依舊是地址所占據(jù)的內(nèi)存空間的大小,所以結(jié)果為 4 或者 8;??

32位平臺

64位平臺

5.2.6:指針存儲字符串(strlen)

int main()

{

char* p = "abcdef";

printf("%d\n", strlen(p));

printf("%d\n", strlen(p + 1));

printf("%d\n", strlen(*p));

printf("%d\n", strlen(p[0]));

printf("%d\n", strlen(&p));

printf("%d\n", strlen(&p + 1));

printf("%d\n", strlen(&p[0] + 1));

return 0;

}

(1):p是個(gè)指針變量,指針存儲的是首元素地址,因此這里的strlen(p)是從字符'a'開始統(tǒng)計(jì),直到遇到\0為止,由于字符串的結(jié)束標(biāo)志是'\0',所以這里的結(jié)果則是6.

(2):p為字符指針,p + 1跳過一個(gè)字節(jié),因此這里的strlen(p + 1)是從字符'b'開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符串的結(jié)束標(biāo)志是'\0',所以這里的結(jié)果則是5.?

(3):指針變量p存儲的是字符串中'a'的地址,對其解引用得到字符'a','a'的ascii碼為97,從地址的角度出發(fā),相當(dāng)于使用strlen函數(shù)去訪問97那一塊地址空間,可是97那塊空間并不是指針變量p所指向的空間,所以發(fā)生了空間的非法訪問,因此這里的結(jié)果是錯(cuò)誤的.

(4):p[0] 等價(jià)于 *(p + 0),因此這里得到'a','a'的ascii碼為97,從地址的角度出發(fā),相當(dāng)于使用strlen函數(shù)去訪問97那一塊地址空間,可是97那塊空間并不是指針變量p所指向的空間,所以發(fā)生了空間的非法訪問,因此這里的結(jié)果是錯(cuò)誤的.???

(5):&p得到的是指針變量p的地址,由于指針變量p的地址后面的內(nèi)容是未知的,因此這里strlen(&p)的結(jié)果是隨機(jī)值.

?

(6):&p得到的是指針變量p的地址,p的地址 + 1以后還是地址,這塊地址后面所指向的內(nèi)容也是未知的,因此這里的strlen(&p + 1)的結(jié)果是隨機(jī)值.??

(7):p[0] 等價(jià)于 *(p + 0),然后對其取地址得到的是字符變量'a'的地址,接下來再對地址 + 1,地址 +1以后依舊是地址并且這里得到的地址是第2個(gè)元素的地址即 'b'的地址,因此這strlen(&p[0]?+ 1)是從 'b'的位置開始統(tǒng)計(jì),直到遇到'\0'為止,由于字符串的結(jié)束標(biāo)志是'\0',所以這里的結(jié)果則是?5.?

5.3:二維數(shù)組

int a[3][4] = { 0 };

printf("%d\n", sizeof(a));

printf("%d\n", sizeof(a[0][0]));

printf("%d\n", sizeof(a[0]));

printf("%d\n", sizeof(a[0] + 1));

printf("%d\n", sizeof(*(a[0] + 1)));

printf("%d\n", sizeof(a + 1));

printf("%d\n", sizeof(*(a + 1)));

printf("%d\n", sizeof(&a[0] + 1));

printf("%d\n", sizeof(*(&a[0] + 1)));

printf("%d\n", sizeof(*a));

printf("%d\n", sizeof(a[3]));

(1):a表示數(shù)組名,并且單獨(dú)出現(xiàn),所以sizeof(a)計(jì)算的是整個(gè)二維數(shù)組的大小,而二維數(shù)組a是一個(gè)3行4列的數(shù)組,每一個(gè)元素類型都是整型,因此sizeof(a) = 3 * 4 * 4 = 48.

(2):a[0][0]訪問的是二維數(shù)組中第一行第一列的元素,因此sizeof(a[0][0])的結(jié)果是 4.

?

(3):a[0]訪問的是二維數(shù)組中的第一個(gè)元素即第一行這個(gè)一維數(shù)組的數(shù)組名,由于數(shù)組名單獨(dú)出現(xiàn)在了sizeof內(nèi)部,因此sizeof(a[0]) 的結(jié)果為 16.?

?

(4):a[0]訪問的是二維數(shù)組中的第一個(gè)元素即第一行這個(gè)一維數(shù)組的數(shù)組名,由于數(shù)組名既沒有單獨(dú)出現(xiàn)在sizeof內(nèi)部,也沒有對其取地址,因此這里的a[0]表示的是第一行這個(gè)一維數(shù)組的首元素地址,+ 1以后還是地址即第一維數(shù)組第二個(gè)元素的地址,因此sizeof(a[0] + 1)的結(jié)果是 4或者8.

?

(5):a[0]訪問的是二維數(shù)組中的第一個(gè)元素即第一行這個(gè)一維數(shù)組的數(shù)組名,由于數(shù)組名既沒有單獨(dú)出現(xiàn)在sizeof內(nèi)部,也沒有對其取地址,因此這里的a[0]表示的是第一行這個(gè)一維數(shù)組的首元素地址,+ 1以后還是地址即第一維數(shù)組第二個(gè)元素的地址,對其解引用得到的是一個(gè)整型元素,因此這里的?sizeof(*(a[0] + 1))的結(jié)果為 4.

?

(6):由于數(shù)組名既沒有單獨(dú)出現(xiàn)在sizeof內(nèi)部,也沒有對其取地址,因此這里的a表示的首元素的地址即第一行的起始地址, + 1以后跳過一行,得到第二行的地址即一維數(shù)組的地址,所以這里的sizeof(a + 1)的結(jié)果為 4 或者 8.?

?

(7):由于數(shù)組名既沒有單獨(dú)出現(xiàn)在sizeof內(nèi)部,也沒有對其取地址,因此這里的a表示的首元素的地址即第一行的起始地址, + 1以后跳過一行,得到第二行的地址即一維數(shù)組的地址,對其解引用訪問整個(gè)數(shù)組,因此這里的sizeof(*(a + 1))的結(jié)果為 16.?

?

(8):a[0]訪問的是二維數(shù)組中的第一個(gè)元素即第一行這個(gè)一維數(shù)組的數(shù)組名,對其進(jìn)行取地址得到一維數(shù)組的地址,那么&a[0]的類型為int (*) [4],地址 + 1以后還是地址,所以sizeof(&a[0] + 1)的結(jié)果為 4或者8.?

?

(9):a[0]訪問的是二維數(shù)組中的第一個(gè)元素即第一行這個(gè)一維數(shù)組的數(shù)組名,對其進(jìn)行取地址得到一維數(shù)組的地址,那么&a[0]的類型為int (*) [4],+1以后跳過的字節(jié)數(shù)為該指針指向元素?cái)?shù)據(jù)類型的大小,即此時(shí)得到第二行的地址,對其解引用訪問整個(gè)一維數(shù)組,所以sizeof(*(&a[0] + 1))的結(jié)果為 16.

?

(10):a表示數(shù)組名,由于數(shù)組名既沒有單獨(dú)出現(xiàn)在sizeof內(nèi)部,也沒有對其取地址,所以a表示的是首元素地址即一維數(shù)組的地址,對其進(jìn)行解引用訪問整個(gè)一維數(shù)組,所以sizeof(*a)的結(jié)果為16.?

?

(11):這里有些uu就會有些疑問,這個(gè)二維數(shù)組明明是3行4列,a[3]訪問的是第四行的數(shù)據(jù),這樣子做豈不是發(fā)生了越界嗎?其實(shí)沒有發(fā)生越界,在之前博主有講到過,sizeof計(jì)算的是操作數(shù)的類型在內(nèi)存空間中所占據(jù)的大小.舉例簡單例子:

那么這里也是同理,編譯器同樣也會進(jìn)行轉(zhuǎn)換,所以這里的sizeof(a[3])等價(jià)與sizeof(a[0]),所以這里的結(jié)果是16.

32位平臺

64位平臺

6:指針運(yùn)算筆試題

6.1:題目1

#include

int main()

{

int a[5] = { 1, 2, 3, 4, 5 };

int *ptr = (int *)(&a + 1);

printf( "%d,%d", *(a + 1), *(ptr - 1));

return 0;

}

首先來看第一題,這里出現(xiàn)了&符號,因此此時(shí)a代表的是整個(gè)數(shù)組的地址,對數(shù)組的地址 +1則跳過整個(gè)數(shù)組,然后對其強(qiáng)制類型轉(zhuǎn)換成整型指針存放到ptr中,那么ptr里面存儲的是 5這個(gè)元素的下一個(gè)元素的地址.

a代表數(shù)組名,由于既沒有單獨(dú)出現(xiàn)在sizeof內(nèi)部,也沒有&符號,因此 a+1這里的a則表示首元素地址,又因?yàn)閿?shù)組在內(nèi)存中是連續(xù)存儲的,因此 a + 1此時(shí)指向的是數(shù)組中的第二個(gè)元素也就是2

ptr由于是整型指針,整型指針 - 1跳過四個(gè)字節(jié),因此此時(shí) *(ptr - 1)的值為5.所以答案是:2,5.

6.2:題目2

//在X86環(huán)境下

//假設(shè)結(jié)構(gòu)體的??是20個(gè)字節(jié)

//程序輸出的結(jié)構(gòu)是啥?

struct Test

{

int Num;

char* pcName;

short sDate;

char cha[2];

short sBa[4];

}*p = (struct Test*)0x100000;

int main()

{

printf("%p\n", p + 0x1);

printf("%p\n", (unsigned long)p + 0x1);

printf("%p\n", (unsigned int*)p + 0x1);

return 0;

}

(1):p為結(jié)構(gòu)體的指針,那么結(jié)構(gòu)體的指針 + 1跳過該結(jié)構(gòu)體所占的字節(jié)數(shù)也就是 20(16進(jìn)制:0x000014),所以 p + 0x1的結(jié)果為0x100014.

?

(2):首先對p進(jìn)行強(qiáng)制類型轉(zhuǎn)換成無符號長整形,那么 + 0x1也就是數(shù)值上的 +1,所以結(jié)果為0x100001.

?

(3):首先對p進(jìn)行強(qiáng)制類型轉(zhuǎn)換成無符號整型指針,那么 + 0x1也就是跳過4(16進(jìn)制:0x000004)個(gè)字節(jié),所以結(jié)果為0x100004.

6.3:題目3

#include

int main()

{

int a[4] = { 1, 2, 3, 4 };

int* ptr1 = (int*)(&a + 1);

int* ptr2 = (int*)((int)a + 1);

printf("%x,%x", ptr1[-1], *ptr2);

return 0;

}

(1):這里出現(xiàn)了&符號,因此此時(shí)a代表的是整個(gè)數(shù)組的地址,對數(shù)組的地址 +1則跳過整個(gè)數(shù)組,然后對其強(qiáng)制類型轉(zhuǎn)換成整型指針存放到ptr1中,那么ptr1里面存儲的是 4這個(gè)元素的下一個(gè)元素的地址,在指針初階博主有講到過 arr[1]----->*(arr + 1),那么prt[-1]------>*(ptr -1),由于ptr為整型指針,因此 - 1跳過4個(gè)字節(jié),那么*(ptr - 1)的結(jié)果為4.

?

(2):a為首元素的地址,將其強(qiáng)制類型轉(zhuǎn)換為int類型,那么在數(shù)值上+1,也就是跳過1個(gè)字節(jié),因此是在1這個(gè)元素所占的4個(gè)字節(jié)中跳過1個(gè)字節(jié)然后將這個(gè)表達(dá)式強(qiáng)制類型轉(zhuǎn)換為整型指針,對其解引用訪問4個(gè)字節(jié),再以%x的方式輸出得到2000000.

6.4:題目4

#include

int main()

{

int a[3][2] = { (0, 1), (2, 3), (4, 5) };

int* p;

p = a[0];

printf("%d", p[0]);

return 0;

}

二維數(shù)組里頭是有三個(gè)逗號表達(dá)式,之前博主講過,逗號表達(dá)式的是特點(diǎn):從左向右依次計(jì)算,整個(gè)表達(dá)式的結(jié)果為最后一個(gè)表達(dá)式的計(jì)算結(jié)果.那么這個(gè)二維數(shù)組等價(jià)于 a = {1,3,5}.

p = a[0],那么p[0] = a[0][0]訪問的是二維數(shù)組的第一個(gè)元素,也就是1.

6.5:題目5

#include

int main()

{

int a[5][5];

int(*p)[4];

p = a;

printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);

return 0;

}

p是個(gè)數(shù)組指針,指向的是一個(gè)元素類型為int,元素個(gè)數(shù)為4的數(shù)組,a為數(shù)組名,代表的是首元素地址,那么a的類型為int (*)[5],有的uu就會想,那這樣子的話,類型合適嗎?其實(shí)不管類型的話,是能夠存的,因?yàn)閍是地址,p是指針變量,指針變量就是用來存儲地址的嘛,但是在編譯時(shí),編譯器會發(fā)出警告.

然后我們看表達(dá)式,這里是地址減地址,那么就是指針減去指針,只是一個(gè)是使用%p的方式輸出,一個(gè)是以整型的方式輸出,p[4][2]等價(jià)與 *(*(p + 4) +2),根據(jù)p的類型我們可以得知,p每次 + 1跳過 4個(gè)整型元素的大小.那么我們來看如下這張圖.

根據(jù)上面的圖再結(jié)合之前在數(shù)組階段我們有講到過,二維數(shù)組在內(nèi)存中是連續(xù)存儲的并且是從低地址到高地址.因此&p[4][2] - &a[4][2]為深藍(lán)色的區(qū)域的地址 - 紫色區(qū)域的地址,結(jié)果為-4

PS:這里以%p的方式輸出-4是輸出的是補(bǔ)碼哦~,這里要將-4的補(bǔ)碼轉(zhuǎn)換為16進(jìn)制,這里博主就不轉(zhuǎn)啦.

6.6:題目6

#include

int main()

{

int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

int *ptr1 = (int *)(&aa + 1);

int *ptr2 = (int *)(*(aa + 1));

printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));

return 0;

}

(1):aa為數(shù)組名,由于有&符號,因此此時(shí)aa代表的是整個(gè)數(shù)組的地址, + 1則跳過整個(gè)數(shù)組的大小,那么ptr1這個(gè)整型指針則指向的是 10這個(gè)元素的下一個(gè)位置. 整型指針 - 1則跳過 4個(gè)字節(jié),所以*(ptr1 - 1)的結(jié)果為 10.

(2):aa為數(shù)組名,由于這里既沒有單獨(dú)出現(xiàn)在sizeof里面,也沒有&符號,所以aa為首元素地址,因此aa的類型為int(*)[5], + 1則跳過 5個(gè)整型元素的大小,此時(shí)aa + 1指向的是第二行的地址,那么對其解引用得到第二行首元素的地址,所以 ptr2指向的是6這個(gè)元素,那么*(ptr2 - 1)的結(jié)果為5.

6.7:題目7

#include

int main()

{

char *a[] = {"work","at","alibaba"};

char**pa = a;

pa++;

printf("%s\n", *pa);

return 0;

}

a為數(shù)組名,由于這里既沒有單獨(dú)出現(xiàn)在sizeof內(nèi)部,又沒有&符號,因此a代表的數(shù)組首元素地址,即第一個(gè)字符串的地址.pa為二級指針,即將第一個(gè)字符串的地址存儲在二級指針pa里頭,然后pa++,由于數(shù)組在內(nèi)存中是連續(xù)存儲的,那么此時(shí)pa指向的第二個(gè)字符串的地址,所以*pa的結(jié)果為at.

6.8:題目8

#include

int main()

{

char *c[] = {"ENTER","NEW","POINT","FIRST"};

char**cp[] = {c+3,c+2,c+1,c};

char***cpp = cp;

printf("%s\n", **++cpp);

printf("%s\n", *--*++cpp+3);

printf("%s\n", *cpp[-2]+3);

printf("%s\n", cpp[-1][-1]+1);

return 0;

}

在做這道題之前,我們首先來畫出每個(gè)變量的布局

(1):**++cpp,由于是前置++,那么首先加+1,此時(shí)cpp指向的c+2這塊內(nèi)存空間,然后對其兩次解引用,第一解引用,訪問到c+2,然后再進(jìn)行解引用,訪問到字符串POINT,所以結(jié)果為POINT.

那么此時(shí)所對應(yīng)的布局為下圖

(2):+號的優(yōu)先級是低于 ++與--還有*的,那么首先執(zhí)行前置++,此時(shí)cpp指向c+1這塊內(nèi)存空間,然后解引用訪問到c+1,對其進(jìn)行--得到c,那么此時(shí)指向的是ENTER這個(gè)字符串,再對其解引用訪問到字符串ENTER,由于是char *指針,因此每一次+1跳過1個(gè)字節(jié),所以+3則跳過3個(gè)字節(jié),此時(shí)從E開始向后打印,直到遇到\0,所以結(jié)果為ER.

此時(shí)所對應(yīng)的布局圖為下圖

(3):*cpp[-2] 等價(jià)于 **(cpp - 2),那么首先cpp -2指向的是 c+ 3這塊內(nèi)存空間,然后對其兩次解引用訪問到FIRST字符串,然后 +3跳過3個(gè)字節(jié),所以結(jié)果為ST.

此時(shí)所對應(yīng)的布局圖為下圖

(4):cpp[-1][-1]等價(jià)于 *(*(cpp-1) -1) + 1,cpp-1訪問到c+2的內(nèi)存空間,然后對其解引用得到c+2,c+2 -1得到 c+1,然后再對其解引用得到NEW字符串,接著 +1跳過1個(gè)字節(jié),那么結(jié)果為EW.

好啦,uu們,關(guān)于指針進(jìn)階的剩下這部分滴詳細(xì)內(nèi)容博主就講到這里啦,如果uu們覺得博主講的不錯(cuò)的話,請動(dòng)動(dòng)你們滴小手給博主點(diǎn)點(diǎn)贊,你們滴鼓勵(lì)將成為博主源源不斷滴動(dòng)力.

柚子快報(bào)激活碼778899分享:c語言 指針進(jìn)階(三)

http://yzkb.51969.com/

好文鏈接

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/18911614.html

發(fā)布評論

您暫未設(shè)置收款碼

請?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄