5、C语言面试笔试--数据组织--数组

1、一维数组

注意:和普通变量一样,定义的未初始化全局数组和静态局部数组存放在BSS段,定义的已初始化全局数据和静态局部数组存放在静态数据区。而函数内定义的局部数组(不包括静态数组)存放在栈空间中。
“长度表达式”可以包含常量,但不能包含变量。也就是说,C语言不允许对数组的大小做动态定义,即数组的大小不依赖于程序运行过程中变量的值。
由于const定义的常量具有变量的性质,这类常量也不能作为定义数组的“长度表达式”,例如“const int NUM=10;int a[NUM];”在C语言中编译错误,在C++中编译正确。

注意,在定义数组时“长度表达式”可以包含常量,但是不能包含变量。
对于局部数组,若没有进行初始化,其所有元素值为垃圾值,若初始化时仅对部分元素赋了初值,其余元素取默认值(数值型为0,字符型为空字符);
除了初始化,数组名不能作为左值,因为,它是一个表示首元素地址的常量例如定义 int a[3]后执行a={1,2,3}是错误的

2、一维数组和指针的区别

在C语言中,规定数组名代表数组的首元素的地址,也就是说,数组名就具有地址的概念,而且是一个地址常量,因此可以将数组名(即在内存中存放该数组的首地址)赋给指针。
在这里插入图片描述
特别注意:数组名a代表的是该数组首元素的地址,而不是数组a的首地址,a与&a[0]的含义相同,如“a=&a[0]”返回真,是正确的比较。

&a表示整个数组的首地址,但是在执行语句printf("%x,%x\n",a,&a);时输出的a和&a是相同的,那么两者有什么区别呢?其中区别主要是步长的不同,a+i=a+isizeof(int),其步长为sizeof(int),即一个数组元素的长度,而&a+i=&a+i(a数组的大小),其中步长为a数组的大小。尽管a和&a的值相同,但表示不同的含义,"&a==a"是错误的比较。
为了清楚地说明&a和a的差别,这里采用地址分级的概念,数组元素的地址称为一级地址(其值可以赋给一级指针),而一级地址的地址称为二级地址,以此类推,不同级别的地址是不能比较的,因为对应的步长不同。一维数组名a是一级地址,而&a中加了一个取地址运算符升级为二级地址。

对于一维数组元素,char s[]=“abc”;
定义的是一个字符数组,所以相当于定义了一些空间来存放“abc”,如果数组s是已初始化的全局数组或者静态局部则存放在静态数据区,如果它是在函数内部定义的局部数组则存放在栈空间中。
对于*p="abc"中的abc是常量,存储在静态局部数据区域。

另外还要特别强调的是*(a+i)a[i] *(p+i) 和p[i]是等价的

p++=1的功能是将p所指的元素修改为1,然后让p指向下一个元素;
++p=1的功能是先执行++p再执行p,先让p指向下一个元素,并将这个元素的值修改为1.
(p)++的功能是先指向p。然后再将
p的值加1;

3、sizeof的使用

指针变量的sizeof:指针变量的sizeof等于计算机内部地址总线的宽度,所以在32位计算机中一个指针变量的返回值必定是4(注意结果是以字节为单位)
数组的sizeof,对数组做sizeof运算等效于对其元素类型做sizeof的结果乘以数组元素的个数,即sizeof返回整个数组在内存中占用的内存字节数。

char a[]="abc";
int b[3];
sizeof(a);	//结果为4,字符末尾还存在一个'\0'结尾符
sizeof(b);//结果为3×4=12(依赖于int的长度)

sizeof的副作用:
sizeof是运算符,跟加减乘除的性质是其实是一样的,在编译的时候就开始执行了,而不是在程序执行时才执行。
sizeof(i++);
其中i++并不执行,因此i++的作用被消除了。

4、二维数组

二维数组元素的引用方式如下:
数组名[下标表达式1][下标表达式2]
其中,下标表达式可以是整型常量或整型表达式。注意不能为变量或者const
对于给了数组部分元素赋初值的,其余自动赋值为0;

int a[3][4]={{1,2,3,4},{5,6,7,8}};

注意允许行,但是不能允许省略列,二维数组在初始化时候必须指定列长度。

由于二维数组a[3][4]也就相当于a={a[0][4],a[1][4],a[2][4]},每个一维数组元素又包含有4个元素。这种降维的思路可以扩展到3维和四维以上的数组。a数组有三行,将它们看成3个一维数组元素,即a={a[0],a[1],a[2]},每个一维数组元素又含有4个元素。这种降维的思路可以扩展到3维或4维以上。
数组名a代表的是该二维数组首元素a[0]的首地址,即a与&a[0]的含义相同.也就是说a与&a[0]的含义相同,“a=&a[0]”返回真,是正确的比较。其中a[0]又和&a[0][0]的含义相同,所以a==&&a[0][0].

二维数组名是一个二级地址(例如**a的结果为a[0][0]),三维数组名是一个三级地址。
&a是整个二维数组的首地址,为三级地址,所以“a==&a”的比较是错误的。
其实,我们只要记住数组名a代表的是首元素的地址,二维数组降解为一维数组来看。
在这里插入图片描述
此外变址运算符号“【】”相当于*(+)
所以a[i][j],*(a[i]+j), *(*(a+i)+j)三者相同都表示第i行j列元素

在这里插入图片描述

5、用一级指针访问二维数组元素

可以把二维数组看成是以一维数组作为元素的二维数组

#include <stdio.h>
#include <malloc.h>
void main()
{

	int i;
	int a[3][2]={{0,1},{2,3},{4,5}};
	int *p=a[1];
	for (i=0;i<2;i++)
		printf("%d",*p++);
}

输出2 3

若有定义int a[3][4] ,不能表示a[1][1]的是()
A、*(&a[0][0]+5)
B、*(*(a+1)+1)
C、*(&a[1]+1)
D、*(a[1]+1)

正确答案C
C选项表示的是a[2][2]

6、字符数组和字符串数组

字符数组的定义
由于C语言中没有直接提供字符串类型,字符串被定义为一个字符数组。例如:

char str[10];

一个字符数组的字符构成一个字符串,这个字符串结束标志是ASCII码为0的字符,即空字符,表示成‘\0’。例如上面定义的str字符数组最多可以存储9个字符,还剩一个字符位置用来存放结尾符。
字符数组初始化的两种方式:

char s[5]={'A','B','C','D','\0'}
char s[5]={"ABCD"}

注意:
与普通数组一样,字符数组名是地址常量,其值为数组本身在内存中存放区域的首地址,即字符串中第一个字符的存储地址,所以赋值语句s="ABCD"是错误的。
初始化少于定义的数组元素的个数,这时候被赋予空格符 (空格符不同于空字符,空字符的ASCII 码为0,空格符的ASCII码为32)。

C语言中常用的字符串处理函数:
字符串数组
字符串数组的定义:它的每个元素都是一个字符串。字符串数组是二维数组。
S【0】表示数组中第一个字符串首元素的地址,为一维地址。
注意S【0】=“ABCD”这种赋值是错误的,因为S【0】是一个地址常量,不允许对它赋值;
而S[0][0]="ABCD"也是错误的,因为S【0】【0】是字符,不是字符串。
使用scanf或者gets函数赋值
使用scanf或者gets函数只能给一个字符串赋值,即每次只能给字符串数组中的一个一维地址的元素赋值。

scanf("%s",name[0]);		//输入的字符串不能含有空格
gets(name[0]);					//输入的字符串可以含有空格

使用标准字符串函数赋值:
使用标准字符串函数strcpy等实现字符串的复制等,例如:

strcpy(name[0],"Smith");

7、strlen函数与sizeof运算符号的差别

strlen函数用于求一个字符串的实际长度,从开始字符到遇见第一个’\0’,如果只定义没有给它赋予初值,这结果是不定的,它会从首地址一直找下去,知道遇到‘\0’停止。sizeof返回的是变量定义后所占内存的字节数,不是实际长度。
例如, char a[5],strlen(a)的结果是不定的,因为数组a没有赋初值,而sizeof(a)的结果为5
strlen的结果是要在执行时才能计算出来,是用来计算字符串的长度,不是类型占内存的大小;而sizeof不能返回动态分配的空间大小。

8、指针数组

当多个基类型相同的指针变量集合成数组时,就形成了指针数组。指针数组时指针的集合,它的每个元素都是一个指针变量。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值