题目一:
int main()
{ //数组名是首元素的地址
//1.sizeof(数组名) - 数组名表示整个数组
//2.&数组名 - 数组名表示整个数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(*&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0]+1));
return 0;
}
int main()
{ //数组名是首元素的地址
//1.sizeof(数组名) - 数组名表示整个数组
//2.&数组名 - 数组名表示整个数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//sizeof(数组名) - 计算的是数组总大小 - 单位是字节 - 16
printf("%d\n", sizeof(a + 0));//4 - 数组名这里表示首元素地址,a+0还是首元素地址,地址大小就是4/8个字节
printf("%d\n", sizeof(*a));//4 - 数组名表示首元素地址,*a就是首元素,sizeof(*a)就是4
printf("%d\n", sizeof(a + 1));//4 - 数组名这里表示首元素地址,a+1是第二个元素的地址,地址的大小就是4/8个字节
printf("%d\n", sizeof(a[1]));//4 - 第二个元素的大小
printf("%d\n", sizeof(&a));//4 &a取出的是数组的地址,但是数组的地址也是地址,地址的大小就是4/8个字节
printf("%d\n", sizeof(*&a));//16 - &a是数组的地址,数组的地址解引用访问数组,sizeof计算的就是数组的大小,单位是字节
printf("%d\n", sizeof(&a + 1));//4/8 &a是数组的地址,&a+1虽然地址跳过整个数组,但还是地址
printf("%d\n", sizeof(&a[0]));//4/8 &a[0]是第一个元素的地址
printf("%d\n", sizeof(&a[0]+1));//4/8 第二个元素的地址
return 0;
}
题目二:
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));// 6 sizeof计算的是数组大小 6*1=6
printf("%d\n", sizeof(arr + 0));//4/8 arr是首元素的地址,arr+0还是首元素的地址 地址的大小是4/8字节
printf("%d\n", sizeof(*arr));//1 arr是首元素地址,*arr是首元素,首元素是字符,大小是一个字节
printf("%d\n", sizeof(arr[1]));//1
printf("%d\n", sizeof(&arr));//4 &arr虽然是数组的地址,但还是地址,地址的大小是4/8个字节
printf("%d\n", sizeof(&arr + 1));//4 &arr+1是跳过整个数组后的地址,地址大小是4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));//4 第二个元素的地址
题目三:
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));//随机值 \0的位置不确定
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));//随机
题目四:
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7 a b c d e f \0 7个字符 7*1=7 sizeof计算的数组的大小。单位是字节
printf("%d\n", sizeof(arr + 0));//4/8计算的是地址的大小 arr+0是首元素的地址
printf("%d\n", sizeof(*arr));//1 *arr是首元素,sizeof(*arr)计算首元素大小
printf("%d\n", sizeof(arr[1]));//1 arr[1]是第二个元素,sizeof(arr[1])计算的是第二个元素的大小
printf("%d\n", sizeof(&arr));//4 &arr虽然是数组的地址,但也是地址,所以是4/8个字节
printf("%d\n", sizeof(&arr + 1));//4/8 &arr+1是跳过整个数组后的地址,但也是地址
printf("%d\n", sizeof(&arr[0] + 1));// 4/8 &arr[0]+1 第二个元素的地址
return 0;
}
数组名是首元素的地址,&和sizeof数组名除外
只有 sizeof(数组名) 的时候,计算的是整个数组的大小,这后面+0,就不是 “纯净的” sizeof(数组名) 了,换句话说只有 sizeof(数组名) 这种特定的形式才是数组大小
题目五:
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;
}
//6 \0之前出现了6个
//6 理由同上
//err
//err
// 6 &arr - 数组的地址 - 数组指针 char(*p)[7]=&arr
//随机值
//5 从b的位置开始数字符
题目六:
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;
}
// 4/8 - p + 1得到的是字符b的地址
//4/8 - 计算指针变量p的大小
//1 *p就是字符串的第一个字符 - 'a'
//1 int arr[10]; arr[0] == *(arr+0) p[0] == *(p+0) == 'a'
//4/8 地址
//4/8 地址
//4/8 地址
题目七:
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;
}
//6
//5
//err
//err
//随机值
// 随机值
//5
题目八:
//二维数组
int main()
{
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]));
return 0;
}
//48 3*4*4
//4
//16 4*4 a[0]相当于第一行作为一维数组的数组名,sizeof(arr[0])把数组名单独放在sizeof()内,计算的是第一行的大小
// 4 - a[0]是第一行的数组名,数组名此时是首元素的地址,a[0]其实就是第一昂第一个元素的地址,所以a[0] + 1就是第一行第二个元素的地址,地址大小是4/8个字节
//4 - *(a[0] + 1) 是第一行第二个元素,大小是4字节
//4 a是二维数组的数组名,没有sizeof(数组名),也没有&(数组名),所以a是首元素地址 而把二维数组看成一维数组时,二维数组的首元素是他的第一行,a就是第一行(首元素)的地址 //a+1就是第二行的地址
//16 sizeof(a[1]) 计算第二行的大小,单位是字节
//4 第二行的地址
//16 计算第二行大小
//a是首元素地址,就是第一行的地址 sizeof(*a)就是计算第一行的大小
//16
总结:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址
3.除此之外所有的数组名都表示首元素的地址
指针笔试题:
题目一:
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
题目二:
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;
}
解析:
指针加减整数的计算,取决于指针类型
答案: 0x00100014 0x00100001 0x00100004
题目三:
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[-1] = ptr+(-1)
答案:4 2000000
题目四:
int main()
{
int a[3][2] = { (0,1),(2,3),(4,5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
解析:
逗号表达式,结果是最后一个表达式结果 - (0,1)结果为1,(2,3)结果为3,(4,5)结果为5
后几位自动用0补齐
答案:1
题目五:
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[4][2] = (*(p + 4) + 2)
+4 — 跳过4个整型
地址 - 地址 = 两个地址之间的元素个数
答案:FFFFFFFC -4
题目六:
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\n", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
解析:
aa[1] - 第二行首元素地址
答案:10,5
几个相等的表达方式:
int arr[10] = { 1,2,3,4,5 };
int* p = arr;
*(p + 2) == p[2] == * (arr + 2) == arr[2]
题目七:
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
解析:
char* p = "abcdef";//字符指针,把常量字符串首字符的地址a放到p中
pa++指向第二个元素
答案:at
题目八:
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;
}
解析:
printf中的++是真实存在的(前后有关联关系,cpp在+的时候在发生变化)
*cpp[-2]+3 == * *(cpp+(-2)) +3
cpp[-1][-1]+1 == *( *(cpp-1) -1 ) +1
答案:POINT, ER, ST, EW
题目九:
int main()
{
unsigned long pulArray[] = { 6,7,8,9,10 };
unsigned long* pulPtr;
pulPtr = pulArray;
*(pulPtr + 3) += 3;
printf("%d,%d\n", *pulPtr, *(pulPtr + 3));
return 0;
}
答案:6,12
题目十:
下面关于指针运算说法镇古鳄的是:()
A.整型指针+1,指针偏移一个字节
B.指针-指针得到的是指针与指针的字节个数
C.整型指针解引用操作访问四个字节
D.指针不能比较大小
答案:C
解析:
A.指针偏移一个整型大小
B.得到的是指针与指针之间的元素个数
D.指针可以比较大小
题目十一:
写一个函数,可以逆序一个字符串的内容
#include<string.h>
#include<assert.h>
void reverse(char* str)
{
assert(str);
int len = strlen(str);
char* left = str;
char* right = str + len - 1;
while (left<right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[256] = { 0 };
scanf("%s", arr);//abcdef --->fedcba
//逆序函数
reverse(arr);
printf("%s\n", arr);
return 0;
}
题目十二:
求0-100000之间的所有水仙花数并输出
#include<math.h>
int main()
{
int i = 0;
for (i = 0; i <= 100000; i++)
{
//判断i是否为水仙花数(自幂数)
//1.计算i的位数 - n位数
int n = 1;
int tmp = i;
int sum = 0;
while (tmp /= 10)
{
n++;
}
//123/10 n++
//12/10 n++
//1/10
tmp = i;
while (tmp)
{
sum += pow(tmp % 10, n);
tmp /= 10;
}
//3.比较i == sum
if (i == sum)
{
printf("%d ", i);
}
}
return 0;
}
题目十三:打印菱形
int main()
{
int line = 0;
scanf("%d", &line);
//打印上半部分
int i = 0;
for (i = 0; i < line; i++)
{
//打印空格
int j = 0;
for (j = 0; j < line - 1 - i; j++)
{
printf(" ");
}
//打印*
for (j = 0; j <2*i+1; j++)
{
printf("*");
}
printf("\n");
}
//打印下半部分
for (i = 0; i < line - 1; i++)
{
int j = 0;
//打印空格
for (j = 0; j <=i; j++)
{
printf(" ");
}
//打印*
for (j = 0; j<2*(line-1-i)-1; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}