C語言——深入理解指針(四)
數組名的意義
- sizeof(數組名),且數組名單獨放在sizeof內部,則這里的數組名表示整個數組,計算的是整個數組的大小
- &數組名,這里的數組名表示的是整個數組,取出的是整個數組的地址
- 除此之外所有的數組名都表示首元素的地址
sizeof和strlen的比較
1.sizeof是操作符,用于計算變量所占內存大小(不關注內存中存放什么數據),單位是字節
2.strlen是庫函數(需要包含頭文件<string.h>),求字符串長度。其統計的是從strlen函數的參數str中這個地址開始向后,\0之前字符串中字符的個數。函數原型:
size_t strlen (const char* str)//返回類型注意為size_t
但若沒有\0,就可能會存在越界查找,結果就是一個隨機數,如下圖所示:
3.比較
實例:
(一)一維數組
這里千萬要注意前面提到的數組名的意義
#include<stdio.h>
int main()
{int a[] = { 1,2,3,4 };
printf("%zu\n", sizeof(a));//16
//a單獨在sizeof里面代表整個數組,即四個元素乘以它們的類型所占字節
printf("%zu\n", sizeof(a+0));//4/8
//a沒有單獨在里面,所以代表首元素的地址,那么a+0還是首元素的地址,這里計算的是一個地址的大小不同環境有差別
printf("%zu\n", sizeof(*a));//4
//這里a沒有單獨放在sizeof內,a就是首元素地址,*a就是首元素1
printf("%zu\n", sizeof(a+1));//4/8
//a是首元素的地址,a+1就是第二個元素的地址
printf("%zu\n", sizeof(a[1]));//4
//第二個元素
printf("%zu\n", sizeof(&a));//4/8
//&a取出的是數組的地址,數組的地址也是地址
printf("%zu\n", sizeof(*&a));//16
//&a取出的是數組的地址,它的類型為int(*)[4]
//對于數組指針解引用,訪問的則是這個數組
printf("%zu\n", sizeof(&a+1));//4/8
//&a是數組的地址,&a+1是跳過數組后的地址
printf("%zu\n", sizeof(&a[0]));//4/8
//第一個元素的地址
printf("%zu\n", sizeof(&a[0]+1));//4/8
//跳過第一個元素的地址,到達第二個元素的地址
return 0;
}
運行結果:
(二)字符數組
(1)操作符sizeof
#include<stdio.h>
int main()
{char arr[] = { 'a','b','c','d','e','f'};printf("%zu\n", sizeof(arr));//6,計算整個數組printf("%zu\n", sizeof(arr + 0));//4/8,首元素的地址printf("%zu\n", sizeof(*arr));//1,*arr就是首元素printf("%zu\n", sizeof(arr[1]));//1,第二個元素printf("%zu\n", sizeof(&arr));//4/8,數組的地址printf("%zu\n", sizeof(&arr + 1));//4/8,依舊是地址printf("%zu\n", sizeof(&arr[0] + 1));//4/8,第二個元素的地址return 0;
}
運行結果:
#include<stdio.h>
int main()
{char* p = "abcdef";printf("%zu\n", sizeof(p));//4/8//p是一個指針變量,我們假設地址0x0012ff30printf("%zu\n", sizeof(p + 0));//4/8//p+1就是b的地址printf("%zu\n", sizeof(*p));//1//char*類型指針解引用只能訪問一個字符printf("%zu\n", sizeof(p[0]));//1//p[0]->*(p+0)->*p,就是第一個元素printf("%zu\n", sizeof(&p));//4/8//&p是指針變量p的地址,是二級指針printf("%zu\n", sizeof(&p+ 1));//4/8printf("%zu\n", sizeof(&p[0] + 1));//4/8//&p[0]+1就是b的地址return 0;
}
(2)庫函數strlen():
#include<stdio.h>
#include<string.h>
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%zu\n", strlen(arr));//隨機值//arr是數組首元素地址,strlen算的是整個數組,由于字符串中找不到\0,所以為隨機值printf("%zu\n", strlen(arr + 0));//隨機值//(arr+0)也是首元素地址printf("%zu\n", strlen(*arr));//程序崩潰//arr是首元素地址,*arr就是首元素即‘a’——97//這里就會出現非法訪問內存printf("%zu\n", strlen(arr[1]));//程序崩潰//同上printf("%zu\n", strlen(&arr));//隨機值//整個數組的地址,從數組的起始位置數字符串的長度,但是沒有\0printf("%zu\n", strlen(&arr + 1));//隨機值//跳過這個數組的地址,向后找\0printf("%zu\n", strlen(&arr[0] + 1));//隨機值//從第二個元素的地址,向后找\0return 0;
}
int main()
{char* p = "abcdef";printf("%zu\n", strlen(p));//6//p就是a的地址,直至遇到\0向后數有6個字符printf("%zu\n", strlen(p+1));//5//p+1指向b,向后數直到遇到\0有五個字符printf("%zu\n", strlen(*p));//error//*p就是第一個字符printf("%zu\n", strlen(p[0]));//error//同上printf("%zu\n", strlen(&p));//隨機值//p變量在內存中后續的空間內容不確定printf("%zu\n", strlen(&p+1));//隨機值//同上printf("%zu\n", strlen(&p[0]+1));//5//&p[0]就是a的地址,&p[0]+1就是b的地址,從b的位置向后數return 0;
}
(三)二維數組
- 這里還是要特別注意:數組名單獨放在sizeof內,表示整個數組
- 還要注意的一個點:sizeof在計算變量,數組的大小時,是通過類型來推導的,不會真實去訪問內存,舉個栗子:
在下圖中,括號內s=a+2,其中a和2都是int類型,算出來s=12,但sizeof并不會去計算,而是看s本身是什么類型,short類型占兩個字節,所以打印出來的仍是2而不是4;而打印s的值時,也不會因為在sizeof里面的算式而改變。
- 實例
#include<stdio.h>
int main()
{int a[3][4] = { 0 };printf("%zu\n", sizeof(a));//48printf("%zu\n", sizeof(a[0][0]));//4printf("%zu\n", sizeof(a[0]));//16//a[0]是第一行一維數組名,單獨放在sizeof內部// 表示第一行這個數組printf("%zu\n", sizeof(a[0]+1));//4/8//a[0]沒有單獨放在sizeof中// 則a[0]是第一行第一個元素的地址,a[0]+1是第一行第二個元素的地址printf("%zu\n", sizeof(*(a[0] + 1)));//4//*(a[0] + 1)是第一行第二個元素printf("%zu\n", sizeof(a+1));//4/8//a未單獨放在sizeof中,表示數組首元素的地址,就是第一行的地址// a+1就是第二行的地址printf("%zu\n", sizeof(*(a+1)));//16//a+1是第二行的地址,解引用就是a[1]這行數組,計算的是整個數組的大小printf("%zu\n", sizeof(&a[0]+1));//4/8//表示第二行的地址printf("%zu\n", sizeof(*( & a[0] + 1)));//16//第二行的地址解引用就是這一行printf("%zu\n", sizeof(*a));//16//a沒有單獨放在里面,是第一行的地址,解引用就是a[0]printf("%zu\n", sizeof(a[3]));//16//sizeof在計算變量,數組的大小時,是通過類型來推導的,不會真實去訪問內存//所以這里不會有越界訪問return 0;
}
我們來測試一下運行結果:
本次內容到這里就結束了,謝謝觀看,如有不對歡迎在評論區留言指正。
心向往之行必能至!