1.大小和长度竟然不是一个意思
(1)、sizeof()和strlen()有什么异同之处?
(2)、他们对于不同的参数结果有什么不同?请试举例子说明。
#include<stdio.h>
int main()
{
char s[]="I Love Linux\0\0\0";
int a=sizeof(s);
int b=strlen(s);
printf("%d %d\n",a,b);
return 0;
}
该程序的输出结果为:16 12
sizeof()是 运算符,返回的是变量声明后所占的内存数(包括字符串的最后一个'\0'),其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等;
strlen()是函数,它用来计算指定字符串的长度,但不包括结束字符(即 遇到NULL字符就停止计算)
2.箱子的大小和装入物品的顺序有关
test1和test2都含有一个short、一个int、一个double,那么sizeof(t1)和sizeof(t2)是否相等呢?这是为什么呢?
#include<stdio.h>
struct test1{
int a;
short b;
double c;
};
struct test2{
short b;
int a;
double c;
};
int main()
{
struct test1 t1;
struct test2 t2;
printf("sizeof(t1):%d\n",sizeof(t1));
printf("sizeof(t2):%d\n",sizeof(t2));
return 0;
}
该程序的输出是:
sizeof(t1):16
sizeof(t2):16该程序中定义了两个结构题t1和t2;根据结构体的内存对齐机制可知:
在t1结构体中,第一个先定义了int类型的变量a,占4个字节(假设地址从0开始),第二个是short类型的变量b,占两个字节,在内存中可以紧跟在变量a之后,第三个定义了一个double类型的变量c占八个字节,因为前两个变量ab在一起一共占用了前面六个字节,c是八个字节就必须从八的倍数处的地址开始存储,因此变量ab之后有两个字节的位置被空了出来,因此结构体t1一共占了16个字节。
如图所示:(t1结构体)
在t2结构体中,内存的如下图所示:
3.哦,又是函数
想必在高数老师的教导下大家十分熟悉函数这个概念。那么你了解计算机程序设计中的函数吗?请编写一个func函数,用来输出二位数组arr中每个元素的值
/*在这里补全func函数的定义*/
int main()
{
int arr[10][13];
for(int i=0;i<10;i++){
for(int j=0;j<13;j++){
arr[i][j]=rand();
}
}
func(arr);
}
代码如下:
#include<stdio.h> #include<stdlib.h> void func(int a[][13], int m, int n); int main() { int arr[10][13]; for(int i = 0;i<10;i++){ for(int j = 0;j<13;j++){ arr[i][j] = rand(); } } func(arr,10,13); return 0; } void func(int a[][13], int m, int n) { for(int i = 0;i<m;i++){ for(int j = 0;j<n;j++){ printf("%d ",a[i][j]); } } }
4.就不能换个变量名吗?
(1)、请结合下面的程序,简要谈谈传值和传址的区别;
(2)、简要谈谈你对C语言中变量的生命周期的认识:
#include<stdio.h>
int ver=123;
void func1(int ver){
ver++;
printf("ver = %d\n",ver);
}
void func2(int *pr){
*pr=1234;
printf("*pr = %d\n",*pr);
pr=5678;//将int类型的数字赋给指针变量,错误
printf("ver = %d\n",ver);//输出全局变量ver:123
}
int main()
{
int a=0;
int ver=1025;
for(int a=3;a<4;a++){
static int a=5;
printf("a=%d\n",a);
a=ver;
func1(ver);
int ver=7;
printf("ver = %d\n",ver);
func2(&ver);
}
return 0;
}
该程序的输出结果是:
a = 5
ver = 1026
ver = 7
*pr = 1234
ver = 123
- 传值:传值,实际是把实参的值赋值给行参,相当于copy。那么对行参的修改,不会影响实参的值 。
- 传址: 实际是传值的一种特殊方式,只是他传递的是地址,不是普通的赋值,那么传地址以后,实参和行参都指向同一个对象,因此对形参的修改会影响到实参。
C语言中的变量及其生命周期:
1、局部变量:
生命周期: 从定义开始, 到该模块结束
作用域: 该模块内2、全局变量:
生命周期: 从定义开始, 到程序结束
作用域: 文件内(用 extern 声明则适用于整个工程)3、static修饰的局部变量:
生命周期:从定义开始,到程序结束
作用域: 该模块内4、static修饰全局变量:
生命周期:从定义开始,到程序结束
作用域: 被限制在该文件内使用
5.套哇真好玩!
请说明下面的程序是如何完成求和的?
#include<stdio.h>
unsigned sum(unsigned n)
{
return n?sum(n-1)+n:0;
}
int main()
{
printf("%u\n",sum(100));
}
利用递归求1+2+3+4........+99+100的值;
第一次调用函数时为100+sum(99);
第二次调用函数时为100+99+sum(98);
以此类推;
直到最后一次100+99+98+.......+1+sum(0)=100+99+98+.......+1+0=5050
6.算不对的算术
#include<stdio.h>
int main()
{
short a=-2;
unsigned int b=1;
b+=a;
int c=-1;
unsigned short d=c*256;
c<<=4;
int e=2;
e=~e|6;
d=(d&0xff)+0x2022;
printf("a=0x%hx\tb=0x%x\td=0x%hx\te=0x%x\n",a,b,d,e);
printf("c=0x%hhx\t\n",(signed char)c);
return 0;
}
输出为:
a=0xfffe b=0xffffffff d=0x2022 e=0xffffffff
c=0xf02020的面试题中讲过C按位运算符和移位运算符这里不做过多介绍
C按位运算符:
(1)二进制反码或按位取反:~
(2)按位与:&
(3)按位或:|
(4)按位异或:^
移位运算符:
(1)左移:<<
(2)右移:>>
本题在计算时,应注意必要时把数字转换成unsigned类型再做计算。
7.指针和数组的恩怨情仇
#include<stdio.h>
int main()
{
int a[3][3]={
{1,2,3},{4,5,6},{7,8,9}};
int(*b)[3]=a;
++b;
b[1][1]=10;
int *ptr=(int *)(&a+1);
printf("%d %d %d\n",a[2][1],**(a+1),*(ptr-1));
return 0;
}
输出:10 4 9
#include<stdio.h> int main() { int a[3][3]={ {1,2,3},{4,5,6},{7,8,9}}; int(*b)[3]=a;//定义一个数组指针指向一个一维数组 ++b; //b+1后指向数组a的第二行 b[1][1]=10; //b的第二行也就是a的第三行的第二个数字赋值为10 int *ptr=(int *)(&a+1); //&a指的是整个数组,&a+1指的是这个数组后面紧跟着的位置 printf("%d %d %d\n",a[2][1],**(a+1),*(ptr-1)); //**(a+1)表示为:数组a首先移动一个int[3]到数组a的第二行,然后双重解引用对二维数组取值即为4 return 0; }
8.移形换位之术
下面有a,b,c三个变量和四个相似的函数。
(1)、你能说出使用这三个变量的值或地址作为参数分别调用这五个函数,在语法上正确吗?
(2)、请找出下面代码的错误。
(3)、const int和int const是否有区别?如果有区别,请谈谈他们的区别;
(4)、const int*和int const *是否有区别?如果有区别,请谈谈他们的区别。
int a=1;
int const b=2;
const int c=3;
void func0(int n){
n+=1;
n=a;
}
void func1(int *n){
*n+=1;
n=&a;
}
void func2(const int *n)
{
*n+=1;
n=&a;
}
void func3(int *const n){
*n+=1;
n=&a;
}
void func4(const int *const n){
*n+=1;
n=&a;
}
- const int 和int const没有区别都是指此int类型的变量不能被修改
- const int*和int const*也没有区别,都是指指针指向的值不能被改变
上面的五个函数中,func2,func3,func4是错误的;
void func2(const int *n) { *n+=1;//n是只读参数,不能赋值; n=&a; } void func3(int *const n){ *n+=1; n=&a;//n是只读指针,不能给n赋值 } void func4(const int *const n){ *n+=1;//n是只读参数,不能赋值; n=&a;//n是只读指针,不能给n赋值 }
9.听说翻转字母大小不影响英文的阅读?
请编写convert函数用来将作为参数的字符串中的大写字母转换为小写字母,将小写字母转换成大写字母。返回转换完成得到的新字符串。
char *convert(const char *s);
int main()
{
char *str="XiyouLinux Group 2022";
char *temp=convert(str);
puts(temp);
return 0;
}
#include<stdio.h> #include<string.h> #include<stdlib.h> char *convert(const char *s); int main() { char *str="XiyouLinux Group 2022"; char *temp=convert(str); puts(temp); free(temp); return 0; } char *convert(const char *s) { int len=strlen(s),i; char*ret=(char*)malloc(sizeof(char)*(len+1)); for(i=0;s[i];i++){ if(s[i]>='A'&&s[i]<='Z'){ ret[i]=s[i]+32; }else if(s[i]>='a'&&s[i]<='z'){ ret[i]=s[i]-32; }else{ ret[i]=s[i]; } } ret[len]='\0'; return ret; }
10.交换礼物的方式
(1)、请判断下面三种Swap的正误,分别分析他们的优缺点;
(2)、你知道这里的do{,,,}while(0)的作用吗?
(3)、你还有其他方式实现Swap的功能吗?
#define Swap1(a,b,t) \
do{ \
t=a; \
a=b; \
b=t; \
}while(0)
#define Swap2(a,b) \
do{ \
int t=a; \
a=b; \
b=t; \
}while(0)
void Swap3(int a,int b){
int t=a;
a=b;
b=t;
}
Swap3是错误的;当调用函数的时候仅仅将ab变量的值传进去了,没有传ab的地址,相当于没有对ab做任何操作,函数运行结束后ab的值不变。
Swap1直接从原函数中传递参数,比较方便;
Swap2在参数中创建交换变量t,作用时间短,且占用内存空间小。
do{,,,}while(0)让循环只做一次//交换一次ab的值
其他的交换方式在2019年的面试题中有提到过;如图:
12.人去楼空
这段代码是否存在错误?谈一谈静态变量与其他变量的异同。
int *func1(void){
static int n=0;
n=1;
return &n;
}
int *func2(void){
int *p=(int*)malloc(sizeof(int));
*p=3;
return p;
}
int *func3(void){
int n=4;
return &n;
}
int main(void)
{
*func1()=4;
*func2()=5;
*func3()=6;
}
func3()函数有错误,之前已经定义过静态变量n之后不能对n重新定义;
静态变量属于静态存储方式,其存储空间为内存中的静态数据区(在 静态存储区内分配存储单元),该区域中的数据在整个程序的运行期间一直占用这些存储空间(在程序整个运行期间都不释放),也可以认为是其内存地址不变,直 到整个程序运行结束
13.奇怪的输出
该题与2020年面试题第八题有异曲同工之妙,可参考2020年第八题解析。