当前位置:网站首页>【C语言进阶篇】数组&&指针&&数组笔试题
【C语言进阶篇】数组&&指针&&数组笔试题
2022-07-04 21:28:00 【沐曦希】
大家好我是沐曦希
文章目录
前言
指针
内存–》内存的单元(1byte字节)–》编号–》地址–》指针
所以指针就是一个地址(编号)而已。
口头语中说的指针一般指:指针变量。指针变量就是一个变量而已,就是一块内存空间,指针变量用来存放地址。
指针变量在x32平台下大小为4个字节,在x64平台下大小为8个字节。
指针运算包括:
1.加减正数
2.指针-指针
3.指针的关系运算
指针也就是内存地址,指针变量是用来存放内存地址的变量,在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。
在 C/C++语言中,指针一般被认为是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组,函数等占据存储空间的实体。
int a = 10;
int* pa = &a;//pa是指针变量,int*是指针变量pa的类型
//*说明pa是指针变量,int说明指针变量pa所指向的变量的类型
*pa = 20;//*pa解引用操作
printf("%d\n",a);//20
指针类型的意义
char ch = 'w';
char* pc = &ch;//字符指针
float a = 3.14f;
float* pf = &a;//浮点数指针
1.指针变量在进行加减整数运算时候,指针变量类型决定指针变量跳过几个字节(步长)。
2.指针变量进行解引用操作的时候,指针变量的类型决定了指针变量一次访问多少个字符(权限)。
指针数组
指针数组:本质上就是数组,数组中存放的是指针(地址)。
int* pa = NULL;//指针变量要初始化,否则为野指针
int* pb = NULL;
int* pc = NULL;
int* pd = NULL;
int* arr[4] = {
pa,pb,pc,pd};//指针数组
数组名
1.数组名在大部分情况下表示:首元素地址。
但有两个例外,下面两个数组名表示整个数组:
1.sizeof(数组名);//求的是整个数组在空间中所占内存的大小
//数组名单独包括在sizeof内
2.&数组名//取出的是整个数组的地址
#include<stdio.h>
int main()
{
int arr[3] = {
1,2,3 };
printf("%d\n", sizeof(arr));//12
printf("%d\n", sizeof(&arr));//4或者8//地址的大小为4或者8,x32是4,x64是8
}
函数指针
函数也是有地址,那么可以用指针变量来存储函数的地址,方便以后的函数调用。
#include<stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pa)(int, int) = &Add;
//函数的地址存放在函数的指针变量中
int (*pb)(int, int) = Add;
int ret = (*pa)(2, 3);
int sum = pb(2, 3);
printf("%p\n", &Add);
printf("%p\n", pa);
printf("%p\n", pb);
printf("%d\n", ret);
printf("%d\n", sum);
return 0;
}
函数指针能实现回调函数。回调函数是通过函数指针调用的函数。
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
函数指针数组
函数指针数组指:本质上是数组,用于存放函数指针的数组。
int (*pf)(int , int ) = Add;
int (*pfArr[4])(int ,int );//int(*)(int ,int )是函数指针数组的类型
pfArr数组的每个元素的类型是:int(*)(int ,int );
pfArr数组可以存放四个类型为int(*)(int ,int )的函数指针。
冒泡排序模拟qsort函数
#include <stdio.h>
int int_cmp(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
void _swap(void* p1, void* p2, int size)
{
int i = 0;
for (i = 0; i < size; i++)
{
char tmp = *((char*)p1 + i);
*((char*)p1 + i) = *((char*)p2 + i);
*((char*)p2 + i) = tmp;
}
}
void bubble(void* base, int count, int size, int(*cmp)(void*, void*))
{
int i = 0;
int j = 0;
for (i = 0; i < count - 1; i++)
{
for (j = 0; j < count - i - 1; j++)
{
if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)
{
_swap((char*)base + j * size, (char*)base + (j + 1) * size, size);
}
}
}
}
int main()
{
int arr[] = {
1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
//char *arr[] = {"aaaa","dddd","cccc","bbbb"};
int i = 0;
bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
数组的笔试题
小沐所用的平台是x32环境下的
笔试题一
代码
//一维数组
#include<stdio.h>
int main()
{
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;
}
解析
1.sizeof(数组名),此时数组名表示整个数组,计算的是整个数组的大小,单位是字节。故为16个字节
2.a+0 中的数组名a不是单独放在sizeof内部,又没有取地址符号,所以a就是首元地址,a+0还是首元素地址,地址的大小为4或者8个字节。故为4或者8个字节
3.*a 中的数组名a是数组首元素的地址,*a就是对首元素的地址解引用,找到的就是首元素,因为首元素的类型为int整型,所以首元素的大小就是4个字节。故为4个字节
4.a+1 中的a是数组首元素的地址,a+1是第二个元素的地址,sizeof(a+1)就是地址的大小4或者8。故为4或者8个字节。
5.a[1] 表示的是第二位元素,故sizeof(a[1])计算的是第二位元素所占内存的大小。故为4个字节
6.&a取出的数组的地址,数组的地址,也就是个地址,而地址的大小是4或者8。故为4或者8个字节。
7.*&a 中的&a的类型是int(*)[4],&a拿到的是数组名的地址,类型是 int(*)[4],是一种数组指针,数组指针解引用找到的是数组,即相当于*和&相互抵消,即*&a等价于a,即求sizeof(a),而a表示整个数组,计算的是整个数组的大小,单位是字节。故为16个字节。
8.&a+1 中的&a取出的是数组的地址,&a的数组指针类型是 int(*)[4],&a+1 是从数组a的地址向后跳过了一个(4个整型元素的)数组的大小,&a+1还是地址,是地址就是4/8字节。故为4或者8个字节。
9.&a[0] 中&a[0]就是第一个元素的地址,计算的是地址的大小。故为4或者8个字节。
10.&a[0]+1 中&a[0]+1是第二个元素的地址,大小是4/8个字节,&a[0]+1相当于&a[1]。故为4个字节。
结果
笔试题二
代码
//字符数组
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = {
'a','b','c','d','e','f' };
//6个元素
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(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));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr + 0));
//printf("%d\n", strlen(*arr));//error
//printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));
return 0;
}
解析
strlen求字符串长度,关注的是字符串中的‘\0’,计算的是’\0’之前出现的字符串的个数,是库函数,只针对字符串。
sizeof只关注占用内存空间的大小,不在乎内存中存放的是什么,是操作符。
1.sizeof(数组名),此时数组名表示整个数组,计算的是整个数组的大小,单位是字节。故为6个字节
2.arr+0 中arr + 0 是数组首元素的地址,地址的大小为4或者8。故为4或者8个字节。
3.*arr 中arr表示首元素的地址,*arr表示首元素,大小为1个字节,故为1个字节。
4.arr[1]表示第二位元素,大小为一个字节。
5.&arr取的是整个数组的地址,地址的大小为4或者8个字节。
6.&arr+1 就是跳过一个数组后的地址,地址的大小为4或者8个字节。
7.&arr[0]+1相当于arr[1],即表示第二位元素,大小为一个字节。
8.strlen(arr) 表示在‘\0’(0)之前的元素个数,所以为随机值
9.strlen(arr+0)相当于strlen(arr),故依然为随机值
10.strlen(arr)相当于strlen(‘a’),又相当于strlen(97),是一个野指针,故是错误的。
11.strlen(arr[1])相当于strlen(‘b’),又相当于strlen(98),是一个野指针,故是错误的。
12.strlen(&arr)取得是整个数组的地址,从首元素开始数,到’\0’结束,即随机值。
13.strlen(&arr+1)表示跳过一个类型为char()[6]的数组,故为随机值-6。
14.strlen(&arr[0]-1)表示从第二位元素开始数,到’\0’结束,即随机值-1.以上的随机值相等
结果
笔试题三
代码
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
//7个元素
//[a b c d e f \0]
printf("%d\n", sizeof(arr));//7
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));//error
//printf("%d\n", strlen(arr[1]));//error
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr + 1));//随机值
printf("%d\n", strlen(&arr[0] + 1));5
return 0;
}
结果
笔试题四
代码
#include<stdio.h>
int main()
{
char* p = "abcdef";
//7个元素
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));//error
//printf("%d\n", strlen(p[0]));//p[0]-->*(p+0)//error
printf("%d\n", strlen(&p));//随机值
printf("%d\n", strlen(&p + 1));//随机值
printf("%d\n", strlen(&p[0] + 1));//5
return 0;
}
结果
笔试题五
代码
#include<stdio.h>
int main()
{
int a[3][4] = {
0 };
printf("%d\n", sizeof(a));//3*4*4=48
printf("%d\n", sizeof(a[0][0]));4
printf("%d\n", sizeof(a[0]));
//a[0]是第一行这个一维数组的数组名,单独放在sizeof内部,a[0]表示第一个整个这个一维数组
//sizeof(a[0])计算的就是第一行的大小
printf("%d\n", sizeof(a[0] + 1));
//a[0]并没有单独放在sizeof内部,也没取地址,a[0]就表示首元素的地址
//就是第一行这个一维数组的第一个元素的地址,a[0] + 1就是第一行第二个元素的地址
printf("%d\n", sizeof(*(a[0] + 1)));
//a[0] + 1就是第一行第二个元素的地址
//*(a[0] + 1))就是第一行第二个元素
printf("%d\n", sizeof(a + 1));
//a虽然是二维数组的地址,但是并没有单独放在sizeof内部,也没取地址
//a表示首元素的地址,二维数组的首元素是它的第一行,a就是第一行的地址
//a+1就是跳过第一行,表示第二行的地址
printf("%d\n", sizeof(*(a + 1)));
//*(a + 1)是对第二行地址的解引用,拿到的是第二行
//*(a+1)-->a[1]
//sizeof(*(a+1))-->sizeof(a[1])
printf("%d\n", sizeof(&a[0] + 1));
//&a[0] - 对第一行的数组名取地址,拿出的是第一行的地址
//&a[0]+1 - 得到的是第二行的地址
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
//a表示首元素的地址,就是第一行的地址
//*a就是对第一行地址的解引用,拿到的就是第一行
printf("%d\n", sizeof(a[3]));
return 0;
}
结果
总结
数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址。
写在最后
友友们觉得不错的可以给个关注,点赞或者收藏哦!感谢各位友友们的支持。
你的️点赞是我创作的动力的源泉
你的收藏是我奋斗的方向
你的关注是对我最大的支持
你的️评论是我前进的明灯
创作不易,希望大佬你支持一下小沐吧
边栏推荐
- 输入的查询SQL语句,是如何执行的?
- [public class preview]: basis and practice of video quality evaluation
- 机器学习笔记 - 互信息Mutual Information
- How to use concurrentlinkedqueue as a cache queue
- How to implement Devops with automatic tools
- Flutter 返回按钮的监听
- Numpy vstack and column_ stack
- Interviewer: what is XSS attack?
- Flutter TextField示例
- Flutter WebView示例
猜你喜欢
Cloudcompare & open3d DBSCAN clustering (non plug-in)
Shutter textfield example
Methods of improving machine vision system
Bookmark
Maidong Internet won the bid of Beijing life insurance
OMS系统实战的三两事
Sorting and sharing of selected papers, systems and applications related to the most comprehensive mixed expert (MOE) model in history
做BI开发,为什么一定要熟悉行业和企业业务?
Exclusive interview of open source summer | new committer Xie Qijun of Apache iotdb community
How is the entered query SQL statement executed?
随机推荐
Golang interview finishing three resumes how to write
gtest从一无所知到熟练使用(3)什么是test suite和test case
MongoDB中的索引操作总结
刘锦程荣获2022年度中国电商行业创新人物奖
Redis has three methods for checking big keys, which are necessary for optimization
minidom 模塊寫入和解析 XML
GTEST from ignorance to proficient use (2) what is test fixture
置信区间的画法
For MySQL= No data equal to null can be found. Solution
Bizchart+slider to realize grouping histogram
flink1.13 sql基础语法(一)DDL、DML
超详细教程,一文入门Istio架构原理及实战应用
HDU - 1078 fatmouse and cheese (memory search DP)
奋斗正当时,城链科技战略峰会广州站圆满召开
Use of class methods and class variables
Three or two things about the actual combat of OMS system
PostgreSQL基本结构——表
SolidWorks工程图添加材料明细表的操作
并列图的画法,多排多列
bizchart+slider实现分组柱状图