C语言 | sizeof和strlen对比&&指针题目

💓个人主页:mooridy
💓专栏地址:C语言
关注我🌹,和我一起学习更多计算机的知识
🔝🔝🔝

sizeof和strlen区别

对比项sizeofstrlen
本质操作符库函数,使用需包含头文件 string.h
功能计算操作数所占内存的大小,单位是字节求字符串长度,统计的是从当前地址向后中找, \0 之前字符的个数
关注点不关注内存中存放什么数据关注内存中是否有 \0,若没有就会持续往后找,可能会越界

数组和指针笔试题

== 数组名的意义:==

  1. sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。
  2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。
  3. 除此之外所有的数组名都表⽰⾸元素的地址。

以下答案均已64位系统为标准(指针变量8字节)

整形数组

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {
    int a[] = { 1,2,3,4 };
    printf("%d\n", sizeof(a));        //单个数组名整个数组,4*4=16
    printf("%d\n", sizeof(a + 0));  
    // a作为表达式使用时,会隐式转换为指向数组首元素的指针,8!!!
    printf("%d\n", sizeof(*a));  
    // a作为表达式使用时,会隐式转换为指向数组首元素的指针,解引用就得到首元素,4
    printf("%d\n", sizeof(a + 1));  
    // // a作为表达式使用时,会隐式转换为指向数组首元素的指针,+1指向数组第二个元素的指针,8
    printf("%d\n", sizeof(a[1]));  // 数组元素,4
    printf("%d\n", sizeof(&a));  // 整个数组的地址,8
    printf("%d\n", sizeof(*&a));  // 整个数组,4*4=16
    printf("%d\n", sizeof(&a + 1));  // 指向数组末尾之后的地址,同样是指针8
    printf("%d\n", sizeof(&a[0]));  // 首元素地址,8
    printf("%d\n", sizeof(&a[0] + 1));  // 指向数组第二个元素的地址,8
    return 0;
}

字符数组

#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)); // arr+0是首元素地址,8
    printf("%d\n", sizeof(*arr)); // *arr是首元素,1
    printf("%d\n", sizeof(arr[1])); // arr[1]是第二个元素,1
    printf("%d\n", sizeof(&arr)); // &arr是数组的地址,8
    printf("%d\n", sizeof(&arr+1)); // &arr+1是跳过整个数组后的地址,8
    printf("%d\n", sizeof(&arr[0]+1)); // &arr[0]+1是第二个元素的地址,8
    return 0;
}
#include <stdio.h>
#include <string.h>

int main() {
    char arr[] = {'a','b','c','d','e','f'};
    printf("%d\n", strlen(arr)); // 因为数组无'\0',会越界找'\0',结果是未定义的
    printf("%d\n", strlen(arr+0)); // 同上面,arr+0是首元素地址,结果未定义
    // 下面代码有错误,strlen需要的是指针参数,而不是字符
    // printf("%d\n", strlen(*arr)); 
    // printf("%d\n", strlen(arr[1])); 
    printf("%d\n", strlen(&arr)); // &arr是数组地址,结果未定义,因为无'\0'
    printf("%d\n", strlen(&arr+1)); // &arr+1是跳过数组后的地址,结果未定义
    printf("%d\n", strlen(&arr[0]+1)); // &arr[0]+1是第二个元素地址,结果未定义
    return 0;
}

结论: strlen关注内存中是否有 \0,若没有会一直往后找,结果未定义。

#include <stdio.h>

int main() {
    char arr[] = "abcdef";
    printf("%d\n", sizeof(arr)); // 字符串包含'\0',有7个元素,7
    printf("%d\n", sizeof(arr+0)); // arr+0是首元素地址,8
    printf("%d\n", sizeof(*arr)); // *arr是首元素,1
    printf("%d\n", sizeof(arr[1])); // arr[1]是第二个元素,1
    printf("%d\n", sizeof(&arr)); // &arr是数组的地址,8
    printf("%d\n", sizeof(&arr+1)); // &arr+1是跳过整个数组后的地址,8
    printf("%d\n", sizeof(&arr[0]+1)); // &arr[0]+1是第二个元素的地址,8
    return 0;
}
#include <stdio.h>
#include <string.h>

int main() {
    char arr[] = "abcdef";
    printf("%d\n", strlen(arr)); // 字符串长度是6,不包含'\0'
    printf("%d\n", strlen(arr+0)); // arr+0是首元素地址,长度是6
    // 下面三行代码有错误,strlen需要的是指针参数,而不是字符
    // printf("%d\n", strlen(*arr)); 
    // printf("%d\n", strlen(arr[1])); 
    printf("%d\n", strlen(&arr)); // &arr是数组地址,长度是6
    printf("%d\n", strlen(&arr+1)); // &arr+1是跳过数组后的地址,结果未定义
    printf("%d\n", strlen(&arr[0]+1)); // &arr[0]+1是第二个元素地址,长度是5
    return 0;
}
#include <stdio.h>

int main() {
    char *p = "abcdef";
    printf("%d\n", sizeof(p)); // p是指针,8
    printf("%d\n", sizeof(p+1)); // p+1是第二个字符地址,8
    printf("%d\n", sizeof(*p)); // *p是首字符,1
    printf("%d\n", sizeof(p[0])); // p[0]是首字符,1
    printf("%d\n", sizeof(&p)); // &p是指针p的地址,8
    printf("%d\n", sizeof(&p+1)); // &p+1是跳过指针p后的地址,8
    printf("%d\n", sizeof(&p[0]+1)); // &p[0]+1是第二个字符地址,8
    return 0;
}
#include <stdio.h>
#include <string.h>

int main() {
    char *p = "abcdef";
    printf("%d\n", strlen(p)); // 字符串长度是6,不包含'\0'
    printf("%d\n", strlen(p+1)); // p+1是第二个字符地址,长度是5
    // 下面三行代码有错误,strlen需要的是指针参数,而不是字符
    // printf("%d\n", strlen(*p)); 
    // printf("%d\n", strlen(p[0])); 
    printf("%d\n", strlen(&p)); // &p是指针p的地址,结果未定义
    printf("%d\n", strlen(&p+1)); // &p+1是跳过指针p后的地址,结果未定义
    printf("%d\n", strlen(&p[0]+1)); // &p[0]+1是第二个字符地址,长度是5
    return 0;
}

二维数组

#include <stdio.h>

int main() {
    int a[3][4] = {0};
    printf("%d\n", sizeof(a));// a 代表整个二维数组,12 * 4 = 48
    printf("%d\n", sizeof(a[0][0]));// a[0][0] :二维数组的第一个元素,4 
    printf("%d\n", sizeof(a[0])); // a[0] 代表二维数组的第一行,一行4元素,16
    printf("%d\n", sizeof(a[0] + 1));
    // a[0] 作为表达式使用时,会隐式转换为指向第一行首元素的指针
    // a[0] + 1 则是指向第一行第二个元素的指针, 8 字节
    printf("%d\n", sizeof(*(a[0] + 1)));
    // *(a[0] + 1) 是对指向第一行第二个元素的指针进行解引用,得到的是该元素本身, 4
    printf("%d\n", sizeof(a + 1));
    // a 作为表达式使用时,会隐式转换为指向二维数组首行的指针
    // a + 1 则是指向二维数组第二行的指针,8
    printf("%d\n", sizeof(*(a + 1)));
    // *(a + 1) 是对指向二维数组第二行的指针进行解引用,得到的是第二行,16
    printf("%d\n", sizeof(&a[0] + 1));
    // &a[0] 是取第一行的地址,&a[0] + 1 则是指向下一行的指针,8
    printf("%d\n", sizeof(*(&a[0] + 1)));
     // 9. sizeof(*(&a[0] + 1))
    // *(&a[0] + 1) 是对指向第二行的指针进行解引用,得到的是第二行,16
    printf("%d\n", sizeof(*a));
    // a 作为表达式使用时,会隐式转换为指向二维数组首行的指针,解引用,得到的是第一行,16
    printf("%d\n", sizeof(a[3]));
    // sizeof 是在编译时计算的,不会实际访问数组元素
    // a[3] 可看作是一个包含 4 个 int 元素的一维数组,所以 sizeof(a[3]) 的结果为 4 * 4 = 16
    return 0;
}

指针运算笔试题

#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+1指向第二个元素地址,解引用就是2
//&a指整个数组地址,&a+1就是指向整个数组后一个位置,用int*强转后,再-1,就只是回退了一个整形,指向了数组最后一个数,5
#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];//p类型为int*,指向第一行第一个元素的地址
	printf("%d", p[0]);
	return 0;
}

//1.逗号表达式的运算规则是从左到右依次计算每个表达式的值,最后整个逗号表达式的值是最后一个表达式的值。
//2.所以(0, 1) 的值是 1,(2, 3) 的值是 3,(4, 5) 的值是 5。
//3.那么数组 a 实际的初始化情况就相当于 int a[3][2] = { 1, 3, 5 };
//a[0] 是二维数组 a 第一行的首地址,这里将其赋值给指针 p ,也就是让 p 指向了 a[0][0] 。
//p[0] 等价于 *(p + 0) ,也就是 p 所指向的元素,也就是 a[0][0] ,其值为 1。
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{
	int a[5][5];
	int(*p)[4];  //数组指针
	p = a;   //指向a前四个元素构成的数组
	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}
//计算 &p[4][2]:
//p 是指向包含 4 个 int 元素的一维数组的指针,
//p[4] 相当于 * (p + 4),也就是让 p 向后移动 4 个包含 4 个 int 元素的一维数组,总共移动了 4 * 4 = 16 个 int 元素的位置。
//p[4][2] 则是在 p[4] 所指向的一维数组里偏移 2 个 int 元素的位置,
//所以 & p[4][2] 相对于 p 起始位置偏移了 16 + 2 = 18 个 int 元素的位置。

//计算& a[4][2]:
 //& a[4][2] 相对于 a 起始位置偏移了 4 * 5 + 2 = 22 个 int 元素的位置。

//指针相减的结果是两个指针之间相差的元素个数,所以 &p[4][2] - &a[4][2] = 18 - 22 = -4。
//在计算机中,负数是以补码形式存储的,-4 的 32 位补码是 0xFFFFFFFC。

//综上所述,程序的输出结果是 0xFFFFFFFC,-4。
#include <stdio.h>
 int main()
 {
	 int aa[2][5] = {
		 1, 2, 3, 4, 5,
		 6, 7, 8, 9, 10
	 };
	 int* ptr1 = (int*)(&aa + 1);   //&aa取得是整个二维数组地址,+1就指向了整个二维数组末尾后一个元素的地址
	 int* ptr2 = (int*)(*(aa + 1));  //aa这里再表达式中就隐式转换为指向第一行数组,+1就是指向第二行数组
	 printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
	 return 0;
	 }

 //*(ptr1 - 1):回退一个元素,就指向10
 //*(ptr2 - 1):会退一个元素就指向5
#include <stdio.h>
  int main()
  {
	  char* a[] = { "work","at","alibaba" };
	  char** pa = a;// pa 指向了 a[0]
	  pa++;
	  printf("%s\n", *pa);
	  return 0;
 }
  //由于 pa 是一个指向 char* 类型的指针,
  //pa++ 会让 pa 向后移动一个 char* 类型的大小,也就是让 pa 指向 a[1]。
  //*pa 是对 pa 进行解引用操作,得到的是 pa 所指向的内容 "at"
#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);
	  printf("%s\n", *-- * ++cpp + 3);
	  printf("%s\n", *cpp[-2] + 3);
	  printf("%s\n", cpp[-1][-1] + 1);
	  return 0;
	  }

c+3:c[3]的地址,即 “FIRST”
c+2:c[2]的地址,即 “POINT”
c+1:c[1]的地址,即 “NEW”
c:c 指向 c[0](即 “ENTER”)
cpp:指向cp[0]

== **++cpp:point==
++cpp:指向cp[1]
一次解引用就是cp[1]本身,c+2
两次解引用,就是c[2],point

*-- * ++cpp + 3:ER
++cpp:将 cpp 再向后移动一个位置,此时 cpp 指向 cp[2]。

  • cpp:对 cpp 解引用,得到 cp[2],也就是 c + 1。
    – * cpp:对 * cpp 进行减 1 操作, * cpp 原本指向 c[1],减 1 后指向 c[0]。
    • – * ++cpp:对-- * cpp 解引用,得到 c[0]。
    • – * ++cpp + 3:将指向 “ENTER” 的指针向后移动 3 个位置,指向字符 ‘E’。
      所以 printf(“%s\n”, *-- * ++cpp + 3); 输出 “ER”。

*cpp[-2] + 3:“ST”
cpp[-2]:等价于* (cpp - 2),此时 cpp 指向 cp[2],cpp - 2 指向 cp[0](即 c + 3,指向 “FIRST”)。

  • cpp[-2]:对 cpp[-2] 解引用,得到 c[3],指向字符串 “FIRST”。
  • cpp[-2] + 3:将指向 “FIRST” 的指针向后移动 3 个位置,指向字符 ‘S’。

cpp[-1][-1] + 1:“EW”
cpp[-1]:等价于* (cpp - 1),此时 cpp 指向 cp[2],cpp - 1 指向 cp[1](即 c + 2,指向 “POINT”)。
cpp[-1][-1]:等价于 * ((cpp - 1) - 1), * (cpp - 1) 得到 c + 2, * (cpp - 1) - 1 得到 c + 1(即 “NEW”), * ((cpp - 1) - 1) 得到 c[1],指向字符串 “NEW”。
cpp[-1][-1] + 1:将指向 “NEW” 的指针向后移动 1 个位置,指向字符 ‘E’。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值