从开学到现在,为了加入一个实验室,参加了很多实验室的纳新,也做了一些面试题。面试题做的让人越来越觉得自己学的C语言知识太少太浅,做完非常有必要总结一番,发现常考又值得学习深挖的有以下几个点。
大端存储和小端存储
大端模式:字数据高字节存储在低地址中,低字节存储在高地址中。
小端模式:高字节存储在高地址当中,低字节存储在低地址当中。
存储如下图:
#include<stdio.h>
union Var
{
long int a;
int b;
}
int main()
{
union Var p;
p.l = 5;
printf("p.l is %d\n",p.i);
p.i = 6;
printf("now p.l is %ld! the address is %p\n",p.l,&p.l);
printf("now p.i is %d! the address is %p\n",p.i,&p.i);
return 0;
}
代码的运行结果:
p.l is 5
now p.l is 6! the address is 0xbfad1e2c
now p.i is 6! the address is 0xbfad1e2c
解释:联合体定义了两个成员i和l。此时i和l都使用同一地址空间,由由于i是最后赋值的变量,自然l也会变为6且地址相同。
关于union类型:
union类型的大小等于其最大数据成员的大小,所有成员公用同一地址起始点,也就是说联合体的访问不管对哪个变量的存取都是从union首地址开始的。(同一时刻只能使用一个数据成员)。
那么怎样判断自己的电脑是大端存储和小端存储呢?
{
typedef union check
{ int i;
char a;
}ch,*p;
ch c;
c.i = 1;
return (c.a == 1);
//int i=1时,1这里在二进制中是低位。若c.a==1,则代表了从低位开始读取(低地址),对应小端。
}
输出的结果很明显了,是小端存储。大多数我们现在是用的电脑都是小端存储。
通过指针修改const变量
当时的面试题是这样的:在不改变const的情况下尝试用更多的方法改变b的值。
int main(int argc,char* argv[ ] )
{
const int b=10;
//自行添加语句,改变变量b的值。
return 0;
}
关于const用法这里我总结了一下:
1.const局部变量存储在堆栈中,可以通过指针修改其值。
2.const变量在预处理时,编译器只对其值读取一次
3.若const全局变量存储在全局存储空间中,其值只有卡度属性,不能进行修改。
const饰数组:
c语言中,const修饰的数组是只读的,修饰的数组空间不可被改变
const修饰指针:
const int p;//p可变,p指向的内容不可变
int const p;//p可变,p指向的内容不可变
int const p;//p不可变,p指向的内容可变
const intconst p;//p和p指向的内容都不可变
const修饰函数参数与返回值:
const修饰函数参数,表示在函数体内,不希望改变参数的值。
const修饰函数的返回值,表示返回值不可变,多用于返回指针。
所以,这道题的答案就是在const int b=10后面加上:
int a=(int*)&b
意为:定义一个指针,指向a变量所代表的内存,然后就可以修改这个指针了。C语言中,const变量只不过是修饰该变量名,它并不能使内存变为只读,但通过指针可以修改被const分配的那个内存。
strlen和sizeof的区别
这个问题已经屡见不鲜了。
很多关于sizeof的解释说他是一个运算符,但是它还有一个非常重要的身份就是关键字之一。
sizeof()用法:
以字节为单位返回一个对象或者类型在内存中所占字节数,包括字符串末尾的空字符。
strlen()函数:
在<string.h>函数库中。用来统计字符串的长度,返回字符串的有效长度,不包括’\0’。
举一个很简单的例子就明白了:
char str[20]="0123456789"
int a=strlen(str);
int b=sizeof(str);
运行结果:a = 10,这是因为strlen计算的是字符串的实际长度,以第一个’\0’为结束符;b = 20,这是因为sizeof计算的是分配的数组str[20]所占的空间大小,不受里面存储内容的影响。
二维数组(个人问题)
定义格式:
元素类型说明符 数组名[行数] [列数] 【=元素初始列表】
说明:用元素类型说明符来定义该数组每个元素的类型。
行数列数分别表示二维数组应有多少行,多少列,即行数代表第一维下标的长度,列数代表第二维下标的长度。他们都是常量表达式。
int b[2][3];说明了一个2行3列的数组,数组名为b。下标变量类型为整型。
二维数组的存放:
在c语言中,二维数组的存放顺序是按行优先存放。二维数组在逻辑上是二维的,其下标在行方向和列方向都有变化。实际的硬件存储器是连续编址的,也就是说在存储单元是按一维线性排列的。
把二维甚至多维的数组存放在一味的内存中常用的方式有两种:一种是按行优先排列,同一行元素连续排列在一起,放完一行后顺序放入下一行;另一种是按列优先排放,同一列元素连续排列在一起,放完一列再顺序放入下一列。由于数组b说明为int类型,占4个字节的内存空间,所以每个元素均占4个字节。
举个栗子:✨
int d[3][5]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
则有数组名维d[0],d[1],d[2]的三个一维数组。每个数组有5 个元素。
参考下图:
d[0]:d[0][0],d[0][1],d[0][2],d[0][3],d[0][4]
d[1]:d[1][0],d[1][1],d[1][2],d[1][3],d[1][4]
d[2]:d[2][0],d[2][1],d[2][2],d[2][3],d[2][4]
再补一个很小的问题,是我纪念第一次面试的时候,学长问的一个基本不能再基本的问题,但是当时学的磕磕绊绊,什么都不懂,在这儿就当警醒以后一直要好好学习,深挖问题。
问题是:||和|有什么区别?
答:首先,||为逻辑操作符,为布尔型,即只有“0”和“1”两种结果
|:位操作符(或)
操作数位位序列,位序列可以是字符型,整型和长短型等(通常情况下选择无符号整型)。
在位运算中,相应的位之间进行逻辑运算,因此,位运算包含多个逻辑运算过程。
这个问题现在看来不过是小儿科,(当时是真的什么都不懂答不上来)。学习什么都是要脚踏实地的)加油吧!