?? ?一維數組:
//數組名a如果既不單獨放在sizeof()中,也不與&結合,那么就表示數組首元素的大小
//a一般表示數組首元素地址,只有兩種情況表示整個數組,sizeof(arr)表示整個數組的大小,&arr表示數組的地址
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//16
printf("%d\n", sizeof(a + 0));//注意:此時a是首元素地址;結果:4/8
printf("%d\n", sizeof(*a));//4
printf("%d\n", sizeof(a + 1));//注意:此時a是第二個元素地址;結果:4/8
printf("%d\n", sizeof(a[1]));//4
printf("%d\n", sizeof(&a));//4/8 注意:是地址
printf("%d\n", sizeof(*&a));//16 注意:&a是數組指針,對數組指針解引用訪問一個數組的大小
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
字符數組:
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
//arr是首元素的地址,*arr就是首元素,站在strlen的角度,認為傳參進去的'a'-97就是地址,97作為地址直接進行訪問就是非法訪問
//strlen不能傳元素,只能傳地址
printf("%d\n", strlen(&arr));//隨機數
printf("%d\n", strlen(&arr + 1));//隨機數
printf("%d\n", strlen(&arr[0] + 1));//隨機數
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7 注意:sizeof()計算字符串大小,有'\0'是需要計算'\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));//隨機數 注意:&arr+1跳過整個數組,指向的位置何時出現'\0'未知
printf("%d\n", strlen(&arr[0] + 1));//5
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
//注意:p,p+1,&p[0]是地址(指針),p[0]是元素,&p,&p+1是二級指針,strlen()中存放指針,計算該指針指向的對象'\0'前的元素個數;如果是二級指針,則計算指向的一級指針'\0'前的元素個數,未知!
二維數組:
//注意:二維數組是一維數組的數組,這個思想非常重要
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 注意:a[0]是第一行這個一維數組的數組名,數組名單獨放在了sizeof內部,計算整個一維數組的大小
printf("%d\n", sizeof(a[0] + 1));//4/8 注意:a[0]是一維數組的數組名,沒有單獨放在sizeof中,表示一維數組首元素的地址,+1表示第二個元素的地址
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
//注意:不會越界,sizeof()中一旦有表達式,就能夠確定類型,sizeof(表達式)在編譯器編譯時就能根據類型計算大小,不需要sizeof真的訪問a
//a[3]==a[0]
//int[4]==int[4]
//表達式有兩個屬性:類型屬性,值屬性
//sizeof使用的是表達式的類型屬性
指針練習題:
練習1:
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1);printf("%d,%d", *(a + 1), *(ptr - 1));return 0;
}
//程序的結果是什么?
// 2 5
練習2:
#include <stdio.h>
//由于還沒學習結構體,這里告知結構體的大小是20個字節
//x86環境下演示
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);//注意:0x1是16進制,實際上就是1;結構體指針+1,就是跳過一個結構體(20個字節);p是16進制,20的16進制是14,結果:00100014//x86環境下,32位地址,地址大小是4字節,16進制打印有8位printf("%p\n", (unsigned long)p + 0x1);//將地址強轉為整型,整型加1就是加1,以%p格式打印,結果:00100001printf("%p\n", (unsigned int*)p + 0x1);//結果:00100004//注意:以%p格式打印時,前面的0不省略return 0;
}
練習3:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1);int* ptr2 = (int*)((int)a + 1);//元素:小端存儲:01 00 00 00,02 00 00 00//首元素地址強轉為整型int后+1,再強轉為int*,表示地址向后跳過一個字節//指向的元素在內存中為00 00 00 02,實際為02000000(16進制)//以%x格式打印,前面的0可以省略printf("%x,%x", ptr1[-1], *ptr2);//4 2000000return 0;
}
練習4:
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//逗號表達式// 1 3 5//a[3][2]={{1,3},{5,0},{0,0}};int* p;p = a[0];//數組名表示首元素地址,p==&a[0][0]printf("%d", p[0]);//p[0]==*(p+0)==*p==a[0][0]//1return 0;
}
練習5:
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;//a-int (*)[5]//p-int (*)[4]//注意:類型不同的指針訪問數組的方式不同printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//FFFFFFFC,-4return 0;
}
指針相減得到兩指針間的元素個數且數組在內存中從低地址向高地址存儲:&p[4][2]-&a[4][2]=-4
-4:
原碼:10000000000000000000000000000100
反碼:1111111111111111111111111111111111011
補碼:1111111111111111111111111111111111100(內存中存儲)
以%p格式打印:補碼即地址(x82—32位—4字節—8個十六進制位):FFFFFFFC
以%d格式打印:-4
練習6:?
#include <stdio.h>
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));//*(aa + 1)==aa[1]==第二行一維數組首元素的地址(注意這個重要變換)/首元素的地址本身就是整型指針,int*強轉是迷惑printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5return 0;
}
練習7:
#include <stdio.h>
int main()
{char* a[] = { "work","at","alibaba" };//字符指針數組:a的元素時字符指針,分別指向"work","at","alibaba"的首個字符char** pa = a;pa++;printf("%s\n", *pa);//atreturn 0;
}
練習8:?
#include <stdio.h>
int main()
{char* c[] = { "ENTER","NEW","POINT","FIRST" };char** cp[] = { c + 3,c + 2,c + 1,c };char*** cpp = cp;printf("%s\n", **++cpp);//注意:前置后置++/--的優先級都高于解引用//地址++,即指向的元素跳過一個//解引用得到c+2,指向c[2],再解引用得到c+2指向的元素,即POINTprintf("%s\n", *-- * ++cpp + 3);//關系運算符的優先級低于解引用和自增操作符//++cp是在上一個cp的前提下++//解引用得到c+1,自減操作得到c,再解引用得到c指向的元素ENTER,+3向后移3個字符,得到ERprintf("%s\n", *cpp[-2] + 3);//*cpp[-2]==*(*(cp-2))==FIRST,+3得到ST//注意:cp-2,cp的值不變printf("%s\n", cpp[-1][-1] + 1);//cpp[-1][-1]==*(*(cpp-1)-1)==ENTER//+1得到EWreturn 0;
}
結果:
POINT
ER
ST
EW?