網站首頁 編程語言 正文
前言:指針與數組的知識往往讓我們無法給自己定位,似乎是懂了,但真的碰上了又一言難盡。接下來有一些關于指針與數組的知識和例題講解,來看看你對指針和數組到底有多了解吧!
指針與數組中的sizeof與strlen
sizeof
sizeof值關注占用空間的大小,單位是字節,不關注元素的類型,是一個操作符。
strlen
strlen是計算字符串中\0之前出現了多少個字符,只針對字符串,是一個庫函數。
數組名
數組名是數組首元素地址,但是在這里有兩個例外:
(1)sizeof(數組名),這里的數組名表示的是整個數組,計算的是整個數組的大小,單位是字節。
(2)&數組名,這里的數組名也表示整個數組,取出的是數組的地址
除了上面兩種情況外,所有的數組名表示的都是數組首元素地址。
下面我們就來看一看數組、指針的一些運用
1、一維數組
整型數組
#include<stdio.h> int main() { //一維數組 int a[] = {1,2,3,4}; printf("%d\n",sizeof(a));// 16 printf("%d\n",sizeof(a+0));// 4/8 printf("%d\n",sizeof(*a));// 4 printf("%d\n",sizeof(a+1));// 4/8 printf("%d\n",sizeof(a[1]));// 4 printf("%d\n",sizeof(&a));// 4/8 printf("%d\n",sizeof(*&a));// 16 printf("%d\n",sizeof(&a+1));// 4/8 printf("%d\n",sizeof(&a[0]));// 4/8 printf("%d\n",sizeof(&a[0]+1));// 4/8 return 0; }
接下來我們就一句一句講解:
sizeof(a)
數組名a單獨放在sizeof內部,計算的是整個數組的大小,單位是字節,所以計算結果:4*4=16個字節。
sizeof(a+0)
a沒有單獨存放,所以表示的是首元素的地址,a+0還是數組首元素的地址,是地址的話大小就是4/8個字節。(在32位環境下為4,64位環境下為8)
sizeof(*a)
a表示的是首元素的地址,*a就是對首元素的地址解引用,所以就是首元素,大小為4個字節
sizeof(a+1)
a表示首元素地址,a+1就是第二個元素的地址,是地址的話大小就是4/8個字節。
sizeof(a[1])
a[1]表示數組的第二個元素,大小是4個字節。
sizeof(&a)
&a表示的是整個數組的地址,數組的地址也是地址,所以大小為4/8個字節。
sizeof(*&a)
&a是數組的地址,類型是int(*)[4],是一個數組指針,如果解引用,訪問的就是4個int的數組,可以理解為*與&抵消效果,所以*&a相當于a,所以sizrof(a)是16。
sizeof(&a+1)
&a是數組地址,&a+1跳過整個數組后的地址,是地址就是4/8個字節大小。
sizeof(&a[0])
&a[0]取出的是數組第一個元素的地址,是地址就是4/8個字節大小。
sizeof(&a[0]+1)
&a[0]+1就是第二個元素的地址,是地址大小就是4/8個字節。
字符數組
#include<stdio.h> int main() { //字符數組 char arr[] = {'a','b','c','d','e','f'}; printf("%d\n", sizeof(arr));// 6 printf("%d\n", sizeof(arr+0));// 4/8 printf("%d\n", sizeof(*arr));// 1 printf("%d\n", sizeof(arr[1]));// 1 printf("%d\n", sizeof(&arr));// 4/8 printf("%d\n", sizeof(&arr+1));// 4/8 printf("%d\n", sizeof(&arr[0]+1));// 4/8 printf("%d\n", strlen(arr));// 隨機值 printf("%d\n", strlen(arr+0));// 隨機值 printf("%d\n", strlen(*arr));// err printf("%d\n", strlen(arr[1]));// err printf("%d\n", strlen(&arr));// 隨機值 printf("%d\n", strlen(&arr+1));// 隨機值 printf("%d\n", strlen(&arr[0]+1));// 隨機值 return 0; }
1、sizeof
sizeof(arr)
arr作為數組名單獨存放在sizeof內部,計算的是整個數組的大小,所以是6個字節。
sizeof(arr+0)
arr沒有單獨存放,所以這里的arr表示的是首元素地址,arr+0還是首元素地址,是地址就是4/8個字節大小。
sizeof(*arr)
arr表示數組的首元素地址,*arr表示的就是首元素,由于是char類型,所以是1字節。
sizeof(arr[1])
arr[1]就是數組中的第二個元素,大小是1字節。
sizeof(&arr)
&arr取出的是數組的地址,地址大小為4/8個字節。
sizeof(&arr+1)
&arr+1跳過了整個數組,還是地址,所以大小為4/8個字節。
sizeof(&arr[0]+1)
&arr[0]是第一個元素的地址,&arr[0]+1就是第二個元素的地址,地址就是4/8個字節。
2、strlen
strlen(arr)
arr是首元素地址,但是arr數組中沒有\0,計算的時候不知道什么時候停止,所以結果是隨機值。
strlen(arr+0)
arr+0還是首元素地址,同上
strlen(*arr)、strlen(arr[1])
strlen需要的是一個地址,從這個地址開始向后計算字符,直到碰上\0停止,統計字符的個數,而*arr是首元素'a',也就是傳給strlen的是'a'的ASCII碼值97,strlen會把97作為起始地址,統計字符串,會形成內存訪問沖突,所以會報錯!arr[1]也一樣,是第二個元素'b'。
strlen(&arr)
&arr是arr數組的地址,雖然類型和strlen的參數類型有所差異,但是傳參過去后,還是從第一個字符的位置向后數字符,而arr數組中沒有\0,所以結果還是隨機值。
strlen(&arr+1)
跳過整個數組,但還是不知道哪里會出現\0,所以結果還是隨機值。
strlen(&arr[0]+1)
&arr[0]表示首元素的地址,&arr[0]+1表示第二個元素的地址,也就是從第二個字符還是往后數,但由于\0不能確定所以還是隨機值。
下面這個就用來自測吧!
#include<stdio.h> int main() { char arr[] = "abcdef"; printf("%d\n", sizeof(arr));// 7 整個數組的大小,包括\0 printf("%d\n", sizeof(arr+0));// 4/8 printf("%d\n", sizeof(*arr));// 1 printf("%d\n", sizeof(arr[1]));// 1 printf("%d\n", sizeof(&arr));// 4/8 printf("%d\n", sizeof(&arr+1));// 4/8 printf("%d\n", sizeof(&arr[0]+1));// 4/8 printf("%d\n", strlen(arr));// 6 printf("%d\n", strlen(arr+0));// 6 printf("%d\n", strlen(*arr));// err printf("%d\n", strlen(arr[1]));// err printf("%d\n", strlen(&arr));// 6 printf("%d\n", strlen(&arr+1));// 隨機值 printf("%d\n", strlen(&arr[0]+1));// 5 return 0; }
指針數組
#include<stdio.h> int main() { char *p = "abcdef"; printf("%d\n", sizeof(p));// 4/8 printf("%d\n", sizeof(p+1));// 4/8 printf("%d\n", sizeof(*p));// 1 printf("%d\n", sizeof(p[0]));// 1 printf("%d\n", sizeof(&p));// 4/8 printf("%d\n", sizeof(&p+1));// 4/8 printf("%d\n", sizeof(&p[0]+1));// 4/8 printf("%d\n", strlen(p));// 6 printf("%d\n", strlen(p+1));// 5 printf("%d\n", strlen(*p));// err printf("%d\n", strlen(p[0]));// err printf("%d\n", strlen(&p));// 隨機值 printf("%d\n", strlen(&p+1));// 隨機值 printf("%d\n", strlen(&p[0]+1));// 5 return 0; }
1、sizeof
sizeof(p)
p是一個指針變量,sizeof(p)計算的是指針變量大小,4/8個字節。
sizeof(p+1)
p是指針變量,用來存放地址的,p+1也是地址,地址大小就是4/8個字節。
sizeof(*p)
*p訪問的是字符a,大小1字節。
sizeof(p[0])
p[0]相當于*(p+0),相當于*p,同上。
sizeof(&p)
&p也是地址,是地址就是4/8個字節。
sizeof(&p+1)
&p是地址,+1是在內存中跳過p變量后的地址,還是地址,所以為4/8字節。
sizeof(&p[0]+1)
p[0]就是a,&p[0]就是a的地址,&p[0]+1就是b的地址,是地址就是4/8個字節。
2、strlen
strlen(p)
這里的p是首元素地址,也就是'a'的地址,strlen(p)就是從'a'的位置向后求字符串的長度,長度是6。
strlen(p+1)
p是首元素地址,p+1就是第二個元素的地址,也就是'b',從b開始數直到\0,所以長度是5。
strlen(*p)、strlen(p[0])
*p、p[0]都是首元素'a',傳的是a的ASCII碼值,會有警報。
strlen(&p)、strlen(&p+1)
&p是指針p的地址,也就是算p的地址的字符串長度,由于不知道什么時候碰到\0,所以是隨機值;&p+1就是跳過p的地址訪問字符,\0未知,所以也是隨機值。如圖:
strlen(&p[0]+1)
&p[0]就是首元素地址,+1就是從第二個元素開始計算,長度為5;p[0]也可以看做*(p+0),也就是*p。
2、二維數組
#include<stdio.h> int main() { //二維數組 int a[3][4] = {0}; printf("%d\n",sizeof(a)); // 48 printf("%d\n",sizeof(a[0][0])); // 4 printf("%d\n",sizeof(a[0])); // 16 printf("%d\n",sizeof(a[0]+1)); // 4/8 printf("%d\n",sizeof(*(a[0]+1)));// 4 printf("%d\n",sizeof(a+1)); // 4/8 printf("%d\n",sizeof(*(a+1))); // 16 printf("%d\n",sizeof(&a[0]+1)); // 4/8 printf("%d\n",sizeof(*(&a[0]+1))); // 16 printf("%d\n",sizeof(*a)); // 16 printf("%d\n",sizeof(a[3])); // 16 return 0; }
?sizeof(a)
這里的a表示的是整個數組,所以大小為4*(3*4)=48。
sizeof(a[0][0])
a[0][0]表示第一行第一列的元素,由于數組是int型,所以一個元素的字節大小為4.
sizeof(a[0])
a[0]表示第一行的數組名,a[0]作為數組名單獨放在sizeof內部,計算的是整個數組大小,即第一行的大小,4*4=16。
sizeof(a[0]+1)
這里的a[0]作為第一行的數組名,沒有&,沒有單獨放在sizeof內部,所以a[0]表示的就是首元素的地址,即a[0][0]的地址,a[0]+1就是第一行第二個元素的地址,是地址就是4/8。
sizeof (*(a[0]+1))
a[0]+1就是第一行第二個元素的地址,對其解引用,就是第一行第二個元素,大小為4。
sizeof(a+1)
a是二維數組的數組名,是類型為 int(*)[4] 的數組指針,沒有&,沒有單獨存放在sizeof內部,a表示首元素的地址,即第一行的地址,a+1就是第二行地址,是地址,大小就為4/8個字節。
sizeof (*(a+1))
(a+1)就是第二行元素的地址,解引用就是第二行的數組名,計算的是第二行的大小,所以大小為16個字節。( *(a+1) --> a[1] )
sizeof(&a[0]+1)
a[0]是第一行,&a[0]是地址,&a[0]+1就是第二行的地址,是地址大小就為4/8字節。
sizeof (*(&a[0]+1))
對第二行的地址解引用,也就是a[1],大小為16字節。
sizeof(*a)
a是二維數組的數組名,沒有&,沒有單獨放在sizeof內部,a表示首元素地址,*a就是二維數組的首元素,也就是第一行,大小為16字節。( *a --> *(a+0) --> a[0] )
sizeof(a[3])
a[3]看起來是越界了,但是計算的時候它會去推導要計算的類型,例如:
int a=10; sizeof(int)和 sizeof(a)計算的大小一樣,它會去推導a的類型是int型。同理,它也會去推導a[3]的類型,a[3]的類型是 int [4],所以大小為16。?
通過上面的一些講解,接下來我們看一些實戰題:
指針筆試題?
筆試題1
#include<stdio.h> int main() { int a[5] = { 1, 2, 3, 4, 5 }; int *ptr = (int *)(&a + 1); printf( "%d,%d", *(a + 1), *(ptr - 1)); return 0; } //程序的結果是什么?
講解 :
?如圖,a是數組名,也就是首元素的地址,a+1就是第二個元素的地址,對(a+1)解引用就是第二個元素2,打印出來2;?
ptr是一個指針,指向的是數組的末尾,且被強制轉換成int *類型,所以ptr-1跳過的是一個int,對其解引用就是數組的最后一個元素5。
筆試題2
#include<stdio.h> struct Test { int Num; char *pcName; short sDate; char cha[2]; short sBa[4]; }*p; //假設p 的值為0x100000。 如下表表達式的值分別為多少? //已知,結構體Test類型的變量大小是20個字節 int main() { p = (struct Test*)0x100000; printf("%p\n", p + 0x1); printf("%p\n", (unsigned long)p + 0x1); printf("%p\n", (unsigned int*)p + 0x1); return 0; }
講解:
已知這里的p是一個結構體指針,p+0x1就相當于結構體指針+1,而這個結構體類型的變量大小是20個字節,也就是加了20個字節,化為十六進制為0x100014;
(unsigned long) p把p強制轉換成unsigned long型,這里的p就相當于是一個無符號類型的數,內存里面就默認為存的就是一個普普通通的整形數字,整型數字加1就是加1,所以結果為0x100001;
(unsigned int *)p把p強制轉換成unsigned int *,這里的p就是整型指針,而整型指針加1就是加4個字節,所以結果為0x100004。
筆試題3
#include<stdio.h> 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; }
如圖,ptr1就是&a+1,跳過整個數組,再強制轉換成int *?型,而ptr1[-1]相當于 *(ptr1-1),也就是跳過一個int * 型,所以ptr1[-1]==4,用%x打印出來也是4;
(int *)((int)a + 1),a是首元素地址,強轉換為int型,也就是把這個地址看成普普通通的整型數字,一個整型數字加1就是簡簡單單的加1,是地址這個數字+1,而不是地址+1,所以跳過的是一個字節。而我們知道數據在內存中的存儲分大小端,這里我們以小端為例,如圖ptr2指向的是一個整型中的第二個字節,從第二個字節開始取出一個整型,以小端輸出,所以結果為02000000。
筆試題4
#include <stdio.h> int main() { int a[3][2] = { (0, 1), (2, 3), (4, 5) }; int *p; p = a[0]; printf( "%d", p[0]); return 0; }
講解:
這里要看清楚題目,數組里面的是圓括號,所以是逗號表達式,數組其實就是
int a[3][2] = { 1, 3, 5 };
p = a[0]?即p指向的是數組的第一行,p[0]就是數組第一行一個元素,所以打印出來是1。
筆試題5
#include<stdio.h> 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是一個數組指針,p指向的數組是4個元素,而a是一個5行5列的數組,如下圖:
好了,今天就講到這里!這些是否讓你對數組和指針有了新的看法呢?
原文鏈接:https://blog.csdn.net/m0_56064145/article/details/122606900
相關推薦
- 2022-04-03 Android?PopUpWindow實現卡片式彈窗_Android
- 2022-07-27 P標簽如何取消上下間隔
- 2022-04-09 關于Python中的閉包詳解_python
- 2023-01-23 Linux?paste命令用法匯總_linux shell
- 2023-12-14 統計字符串內某個字符出現的次數
- 2022-03-31 C語言運算符的重載詳解_C 語言
- 2022-10-02 C++?電話號碼的字母組合功能實現_C 語言
- 2022-06-25 python+opencv實現堆疊圖片_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支