C语言---面试之数据类型篇
Posted 今天天气眞好
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言---面试之数据类型篇相关的知识,希望对你有一定的参考价值。
1.用变量a给出下列定义
(1)一个整型数:int a;
(2)一个指向整型数的指针(一重指针):int* a;
(3)一个指向指针的指针,他指向的指针是指向一个整型数的指针(二重指针):int **a;
(4)一个有10个整型数的数组:int a[10];
(5)一个有10个指针的数组,这10个指针是指向整型数的(指针数组):int* a[10];
(6)一个指向有10个整形数数组的指针(数组指针):int (*a)[10];
(7)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(函数指针):int *a(int)
(8)一个有10个指针的数组,这10个指针均指向函数,该函数有一个整型参数并返回一个整型数(函数指针数组):int (*a[10])(int)
2.下面代码输出是什么,为什么?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b>6)?printf(">6"):printf("<=6");
}
答案:输出结果为“>6”
解读:当运算符中存在有符号数和无符号数的时候,有符号数隐式转换成了无符号数(即底层的代码不变,但是此数从有符号数变成了无符号数)。注意,正数的补码为其本身,负数的补码是其反码加1,因此-20变成了一个非常大的正数,所以最后相加结果肯定“>6”。
3.写出float与"零值"比较的if函数
答案:if(x>=-0.000001 && x<=0.000001);
解读:因为计算机在处理浮点数的时候是有误差的,因此不能将浮点型变量用“==”或者“!=”来与数字进行比较,应该设法转换成“>”或者"<"此类形式。同时注意float的有效数字为6~7位。
4.下面代码有什么错误?
#include <stdio.h>
void main()
{
char *s = "AAA";
s[0] = 'B';
printf("%s",s);
}
答案:
(1)“AAA”是字符串常量,s是指针,指向这个字符串常量,所以申明s的时候就有问题,应该加上const。
(2)因为是常量,所以对s[0]的赋值操作是不合法的。
5.下面代码输出什么?
void main()
{
int *a = (int *)2;
printf("%d",a+3);
}
答案:14
解读:代码将数值2强制类型转换为int *类型指针,int指针类型加3相当于指针后面第三个int类型变量的首地址,int类型变量占用4字节,所以加3相当于指针往后移动了12个字节,指向地址14处。
6.下面代码运行后会是什么现象?
#include <stdio.h>
#define N 500
void main()
{
unsigned char count;
for(count=0;count<N;count++)
{
printf("--%d--\\n",count);
}
}
答案:进入不断打印count值的死循环
解读:因为unsigned char类型的变量最大值为255
,所以count只能从0一直增加到255,然后又恢复为0,无法退出for循环。
7.下面函数的返回值是?
int foo(void)
{
int i;
char c = 0x80;
i = c;
if(i > 0)
return 1;
return 2;
}
答案:返回值为2
解读:因为0x80 == 128,超过了char类型变量c的表示范围(-128~127),所以c == -128,进而i == -128,i < 0.
8.结构体内存对齐原则是?
答案:
(1)第一个成员的首地址(地址偏移量)为0
(2)成员对齐:以4字节为例,如果自身类型小于4字节,则该成员的首地址是自身类型大小的整数倍。如果自身类型大于等于4字节,则该成员的首地址是4的整数倍。若内嵌结构体,则内嵌结构体的首地址也要对齐,只不过自身类型大小用内嵌结构体的最大成员类型大小来表示。数组可以看成拆分为n个数组元素,不用整体看作一个类型。
(3)最后结构体总总体补齐:以4字节对齐为例,如果结构体的最大类型成员小于4字节,则大小补齐为结构体中最大成员类型大小的整数倍;如果大于等于4字节,则大小补齐为4的整数倍。内嵌结构体也要补齐。
注意:32位编译器,一般默认对齐方式是4字节。
9.结构体内存对齐的原因?
(1)平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据
(2)性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐,因为访问未对齐的内存,处理器需要做两次内存访问,而访问对齐的内存仅需要一次。
如下图所示,访问对齐的short变量只需要一次,而访问未对齐的int变量则需要访问两次
10.结构体内存分配的原则?
(1)结构体中元素按照定义顺序存放在内存中,但并不是紧密排列
。从结构体存储的首地址开始,每一个元素存入内存的时候,他都会认为内存是以自己的宽度来划分空间的,因此元素存放的位置一定是以自己的宽度来划分空间的。
(2)在原则一的基础上,检查计算出的存储单元是否为所有元素中最宽的元素长度的整数倍。若是,则结束;若不是,则将其补齐为他的整数倍。
11.在32位操作系统中,有如下结构体,那么sizeof(fun)的数值为?
#pargma pack(1)
struct fun
{
int i; 4字节
double d; 8字节
char c; 1字节
};
答案:sizeof(fun)得到的结果为13
解读:因为预处理语句“#pargma pack(1)”
将编译器的字节对齐改为1了,根据结构体内存对齐原则,共占用13字节
12.数组首元素地址与数组地址的异同?
(1)异
:不同的概念,举个例子:int a[10]
a的值是数组首元素的地址,所以a+1就是第二个元素的地址,int类型占用4字节,所以两者相差4,。而&a是数组地址,所以&a+1就是向后移动(10*4)个单位,所以两者相差40。
(2)同
:数组首地址和数组地址的值是相等的。
13.下面代码输出什么?
#include <stdio.h>
void main()
{
int a[5] = {1,2,3,4,5};
int *p = (int *)(&a + 1);
printf("%d %d",*(a+1),*(p-1));
}
答案:输出:2 , 5
解读:
a是数组首元素地址,所以*(a+1)
就是第二个元素a[1],即2
&a是数组地址,所以&a+1
就是整个数组结尾的下一个地址,*(p-1)就是a[4],即5
14.判断下列表达式正确与否?
(1)char str[2][3] = {"a","b"}
;
正确
,str是一个可存放两个字符串的字符串数组
(2)char str[2][3] = {{1,2},{3,4},{5,6}}
;
错误
,行列不匹配
(3)char str[] = {"a","b"}
;
错误
,字符数组不能存放字符串
(4)char str[2] = {"a","b"}
;
错误
,字符数组不能存放字符串
注意:C语言中字符用' '
括起来,而字符串用“”
括起来
15.查看下列代码,p[6]等于?
int a[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = &a[1];
答案:等于8
解读:p是一个int类型的指针,指向a[1],p[6]表示p往后移动了6个单位(每个单位占据4字节)并解引用,因此p[6] = 8。
16.下面代码的输出结果为?
#include <stdio.h>
void main()
{
char *str[] = {"ab","cd","ef"."gh","ij","kl"}; //指针数组
char *t;
t = (str + 4)[-1];
printf("%s",t);
}
结果:输出“gh
“
解读:str表示数组首元素地址,str + 4表示数组第五个元素地址,(str + 4)[-1]表示在第五个元素地址的基础上往前移动一个元素并解引用,因此输出的是第四个元素。
17.变长数组是什么?
在C99标准中,允许定义数组时[]中的值是整型变量
或者整型表达式
,比如下面这个例子:
void main()
{
int n;
scanf("%d",&n);
int arr[n];
}
18.bool类型包含在哪个头文件中?
答案:stdbool.h
19.结构体struc
t和联合体union
的区别?
(1)两者最大的区别在于内存的使用
(2)结构体各成员拥有自己的内存,各自使用且互不干涉,遵循内存对齐原则;联合体所有成员公用一块内存,并且同时只能有一个成员可以得到这个内存的使用权。一个联合体变量的总长度至少能够容纳最大的成员变量,且需要进行内存补齐。
20.执行完下列代码,c的值为多少?
unsigned int a = 1;
int b = 0;
int c = 0;
c = a + b > 0 ? 1 : 2;
答案:c的值为1
解读:有符号数和无符号数一起运算时候,有符号数转换为无符号数。有符号数int b = 0在内存中的补码是0,因此转换为无符号数之后任然是0,a+b==1>0,因此c = 1.
以上是关于C语言---面试之数据类型篇的主要内容,如果未能解决你的问题,请参考以下文章