当前位置: 首页 > news >正文

C语言笔记(指针题目)例题+图解

        本文分为两部分 ,第一部分为数组、字符串、字符指针在sizeof和strlen中的辨析,第二部分是一些笔试题目。若有错误,请批评指正。

目录

1.第一部分

1.1.数组名的使用

1.1.1一维整型数组在sizeof中的使用

1.1.2一维字符数组在sizeof中的使用

1.1.3一维字符数组在strlen中的使用

1.1.4.一字符串在sizeof中的使用

1.1.5.一字符串在strlen中的使用

1.2字符指针在sizeo和strlen中的使用

1.2.1 字符指针在sizeof中的使用

1.2.2 字符指针在strlen中的使用

2.第二部分(指针笔试题)


1.第一部分

注意:

1.sizeof()是操作符,只关注占用的内存空间的大小,单位是字节,不访问内存中的存储的内容。
2.strlen()是库函数,用来求字符串的长度,统计的是字符'\0'出现之前的字符的个数,当函数在内存中找到’\0‘才算结束,所以strlen可能会越界访问。

3.数组名字的意义

        1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
        2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
        3. 除此之外所有的数组名都表示首元素的地址。

1.1.数组名的使用
1.1.1一维整型数组在sizeof中的使用
int main()
{int a[] = { 1,2,3,4 };printf("%d\n", sizeof(a));  //16 ()中只有数组名,表示整个数组,所测量的是整个数组printf("%d\n", sizeof(a + 0));//a+0就是数组首元素的地址,地址的大小为4个字节printf("%d\n", sizeof(*a));//*a表是的数组首元素,是一个整型变量 4个字节//a不是单独存在时,表示的首元素地址,*a就是元素  1 printf("%d\n", sizeof(a + 1));//a为首元素地址,+1之后还是地址  4个字节printf("%d\n", sizeof(a[1]));// 数组第二个元素  4个字节printf("%d\n", sizeof(&a));//&a数组指针,地址为 4个字节printf("%d\n", sizeof(*&a));// * & 两者相互抵消,是整个数组, 16个字节printf("%d\n", sizeof(&a + 1));//是地址,指向的是第二个元素, 4个字节printf("%d\n", sizeof(&a[0])); //首元素地址  4个字节printf("%d\n", sizeof(&a[0] + 1)); //第二个元素地址  4个字节return 0;
}
1.1.2一维字符数组在sizeof中的使用
int main()
{char arr[] = { 'a','b','c','d','e','f' };//char类型数据大小为一个字节printf("%d\n", sizeof(arr));// 6个字节,arr单独存放,是整个数组printf("%d\n", sizeof(arr + 0));//一个字节,(arr+0)表示为arr[0]printf("%d\n", sizeof(*arr));// 1个字节 ,arr表示首元素地址,*arr为首元素'a'printf("%d\n", sizeof(arr[1]));// 1个字节,第二个元素'b'printf("%d\n", sizeof(&arr));//4个字节  数组指针,&arr为地址printf("%d\n", sizeof(&arr + 1));//4个字节  地址加1还是地址,数据类型不变printf("%d\n", sizeof(&arr[0] + 1));//4个字节 取首元素的地址,+1还是地址return 0;
}
1.1.3一维字符数组在strlen中的使用

        strlen 的返回值是字符的个数,形式参数是字符指针

size_t strlen ( const char * str );

  size_t                无符号整型,返回值

 const char * str  字符指针,形式参数  const为关键字限定str无法修改

int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%d\n", strlen(arr));	//随机值,arr为数组的首元素地址,但是数组中没有'\0'printf("%d\n", strlen(arr + 0));//arr+0,arr是地址+0之后还是地址,函数无法接受,printf("%d\n", strlen(*arr));	//表示是'a'— 97,非法访问,printf("%d\n", strlen(arr[1])); //表示是'b'— 98,非法访问printf("%d\n", strlen(&arr));   //数组指针,是指针会报警的,但是从数组指针开始计算还是随机值printf("%d\n", strlen(&arr + 1));// 数组指针,+1 之后地址跳过数组,随机值printf("%d\n", strlen(&arr[0] + 1));//表示的是第二个元素的地址,也是随机值return 0;
}
1.1.4.一字符串在sizeof中的使用
int main()
{char arr[] = "abcdef";//数组中的元素是 a b c d e f \0  共7个元素printf("%d\n", sizeof(arr));	// 7个字节,数组名字单独存放就是整个数组printf("%d\n", sizeof(arr + 0));//4个字节 arr+0表示&arr[0],首元素地址printf("%d\n", sizeof(*arr));	// 一个字节printf("%d\n", sizeof(arr[1])); // 一个字节printf("%d\n", sizeof(&arr));	// 四个字节printf("%d\n", sizeof(&arr + 1));// 四个字节printf("%d\n", sizeof(&arr[0] + 1));// 四个字节return 0;
}
1.1.5.一字符串在strlen中的使用

        数组名在strlen函数中仍然是首个元素的地址。

int main()
{char arr[] = "abcdef";//数组中的元素是 a b c d e f \0  共7个元素printf("%d\n", strlen(arr)); // 6 字符串中有6个字符 '\0' 不算在内printf("%d\n", strlen(arr + 0));//6 表示&arr[0],首元素的地址,printf("%d\n", strlen(*arr));//*arr是'a',非法访问 printf("%d\n", strlen(arr[1]));//arr[1]是'b',属于非法访问printf("%d\n", strlen(&arr));//6  &arr是数组指针,printf("%d\n", strlen(&arr + 1));// 5 &arr是数组指针,但是其指向的仍然是数组的首元素处// +1 之后指向数组的第二个元素,跳过了第一个元素  printf("%d\n", strlen(&arr[0] + 1));// 5  一个元素的地址 +1 跳过了 第一个元素return 0;
}

1.1.6二维数组在sizeof中的使用

        二维数组的数组名表示的是首行元素的地址,是数组指针。arr[0]是第一行数组。

int main()
{int a[3][4] = { 0 };printf("%d\n", sizeof(a));// 48个字节,一共12个元素,一个元素 4个字节printf("%d\n", sizeof(a[0][0]));// 第一个元素, 4 个字节printf("%d\n", sizeof(a[0]));// 第一行数组  a[0]是第一行数组的名字,单独存在即一个数组  16个字节printf("%d\n", sizeof(a[0] + 1));//a[0]为首元素地址,+1跳到第二个元素地址,4个字节printf("%d\n", sizeof(*(a[0] + 1)));// 4个字节  第二个元素printf("%d\n", sizeof(a + 1));// a + 1表示是a[1]是第二行地址 4个字节printf("%d\n", sizeof(*(a + 1)));// 表示的是第二行的数组, 16个字节printf("%d\n", sizeof(&a[0] + 1));// &a[0]是第一行的地址,+1 指是第二行的地址, 4个字节printf("%d\n", sizeof(*(&a[0] + 1)));//第二行有四个元素, 16个字节printf("%d\n", sizeof(*a));//a为首元素地址,就是第一行的地址, 16个字节printf("%d\n", sizeof(a[3]));//访问的是数组的第四行元素,数组越界,但是可以计算,//sizeof()中表达式是不会计算的,不会访问真是的空间,按照类型出的结果。// *a -- *(a+0) -- a[0]return 0;
}
1.2字符指针在sizeo和strlen中的使用
1.2.1 字符指针在sizeof中的使用
int main()
{char *p = "abcdef";printf("%d\n", sizeof(p));//p为指针 4个字节printf("%d\n", sizeof(p + 1));// +1 跳出整个字符串地址4个字节printf("%d\n", sizeof(*p));// p 指向的第一个元素 *p 就为 'a'  1个字节printf("%d\n", sizeof(p[0]));// p[0] --*(p+0),首个元素   1个字节printf("%d\n", sizeof(&p));//  二级指针   4个字节 printf("%d\n", sizeof(&p + 1));// 二级指针 +1 还是指针 4个字节printf("%d\n", sizeof(&p[0] + 1));//第一个元素的指针 +1 表示的第二个元素的指针 4个字节 return 0;
}
1.2.2 字符指针在strlen中的使用
int main()
{char *p = "abcdef";printf("%d\n", strlen(p));// p是一个指向'a'的一个字符指针, 6printf("%d\n", strlen(p + 1));// 5 指针+1  指针指向的是 'b'printf("%d\n", strlen(*p));// 非法访问printf("%d\n", strlen(p[0]));// 相当于 *(p+0)非法访问printf("%d\n", strlen(&p));// 二级指针 随机值printf("%d\n", strlen(&p + 1));// 随机值 printf("%d\n", strlen(&p[0] + 1)); //5 &p[0]相当于p了 , p+1指向第二个元素return 0;
}

2.第二部分(指针笔试题)

本部分共八个题目

1.

int main()
{int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);           // &a+1 已经跳出整个数组了 //强制转换成int*类型的指针 printf("%d,%d", *(a + 1), *(ptr - 1));//(a+1)中的a为首元素地址 a+1 只想第二个元素return 0;							  
}
//结果为 2,5  

分解

(&a + 1)

        &a指向是数组的首个元素的地址,&a+1跳过整个数组,int(*)[5]数组指针转换成int* 指针ptr-1指向的是第五个元素。

2.

#include <stdio.h>
struct Test
{int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//结构体的大小是20字节
int main()
{int p = 0x100000;printf("%p\n", p + 0x1);//p+1 0x100000+0x1=0x100001printf("%p\n", (unsigned long)p + 0x1);//强制转换成 无符号整型 0x100001printf("%p\n", (unsigned int*)p + 0x1);//强制转换成无符号整型指针 +1 就是+0x4  结果为 0x100004 return 0;
}

3.

//机器为小端存储
int main()
{int a[4] = { 1, 2, 3, 4 };int *ptr1 = (int *)(&a + 1);int *ptr2 = (int *)((int)a + 1);//a为数组的第一个元素的指针,强制转换成int 图解//数组a 的存储方式 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00printf("%x,%x", ptr1[-1], *ptr2);//ptr[-1]-- *(ptr-1)return 0;
}
//结果 0x4 ,0x2000000//%x就是打印16进制的字符

数组元素的存储方式为小端存储,图解

数组在内存中的存储方式:

        a为数组名,是首元素地址,强制转化成int类型,+1之后相当于字符类型+1,增加一个字节,强制转换成int*类型,相当于指向第一个整型元素的第2个字节,*ptr,需要从低地址到高地址四个字节。因此 *ptr就是 0x2000000 

4.

#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };//int a[3][2] = {1,3,5};int *p;p = a[0];//a[0]是第一行的数组名,是第一行的首元素地址printf("%d", p[0]);//p[0] -- *(p+0)return 0;
}

        (0,1)逗号表达式,表达式从左向右,最后表达式的结果就是整个表达式的结果。

5.

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;//二者的步长一致,相差为4  图解//fffffffc  -4
}

a等价于 int (*)[5] 指向是元素为5的数组
p等价于 int (*)[4] 指向是元素为4的数组
根据图&p[4][2] - &a[4][2]相差四个元素 结果为-4
-4 的原码 10000000 00000000 00000000 00000100反码 10000000 00000000 00000000 00000011补码 11111111 11111111 11111111 111111100 地址不会区分原码、反码 、补码,地址就是内存中存储的补码。转换成16进制 ff ff ff fc 

6.

7.

8.


http://www.mrgr.cn/news/59280.html

相关文章:

  • 【算法——1维动态规划具体例题】
  • LeetCode每日一题3185---构成整天的下标对数目 II
  • gin入门教程(10):实现jwt认证
  • 头歌——人工智能(机器学习 --- 决策树2)
  • Lucas带你手撕机器学习——岭回归
  • C#从零开始学习(用户界面)(unity Lab4)
  • Ubuntu安装repo
  • B+Tree简介
  • (done) 有服务器的权限时,如何查看服务器监听的端口?
  • Java中的声明和创建
  • 基于Multisim的音频放大电路设计与仿真
  • 【算法】拓扑排序
  • 大模型,多模态大模型面试问题基础记录24/10/24
  • 【SQLite】改善默认输出格式不直观难以阅读问题:通过修改输出设置提升数据可读性
  • JavaScript part2
  • 【mysql进阶】4-3. 页结构
  • stm32 gpio基础操作和中断操作
  • VulkanTutorial(6·VkSwapChainKHR)
  • RV1126音视频学习(二)-----VI模块
  • 【C++开篇】
  • Java中为什么要私有化构造方法
  • linux快速升级cmake(非源码编译)
  • codimd更改登录超时时限
  • Linux的makefile与进度条小程序实践
  • 刚面完字节!问了大模型微调SFT,估计凉了
  • 国考报名别忘了确认缴费(需传照片)