总言
一些代码分析题,查缺补漏。
会慢慢学习和补充。
一、关于自定义类型
1)、计算结构体的大小
涉及知识点:结构体对齐
结构体的对齐规则:
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8- 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
题一:
#include<stdio.h>
struct S1
{
char c1;//1
int i;//4
char c2;//1
};
int main(void)
{
printf("%d\n", sizeof(struct S1));
return 0;
}
题二:
#include<stdio.h>
struct S2
{
char c1;//1
char c2;//1
int i;//4
};
int main(void)
{
printf("%d\n", sizeof(struct S2));//8
return 0;
}
ps:此处图片截图中sizeof计算的应是struct S2,为笔误。
题三:
#include<stdio.h>
struct S3
{
double d;
char c;
int i;
};
int main(void)
{
printf("%d\n", sizeof(struct S3));//16
return 0;
}
解析:vs环境,32位机
一个double,8字节,偏移量0-7;
一个char,1字节,偏移量8;
一个int,4字节,偏移量12-15;
大小为16,为最大对齐数4的倍数。
题四:
#include<stdio.h>
struct S3
{
double d;
char c;
int i;
};
struct S4
{
char c1;
struct S3 s3;
double d;
};
int main(void)
{
printf("%d\n", sizeof(struct S4));//32
return 0;
}
2)、位段相关
题一:
有如下宏定义和结构定义,当A=2, B=3时,pointer分配( )个字节的空间。
#define MAX_SIZE A+B
struct _Record_Struct
{
unsigned char Env_Alarm_ID : 4;
unsigned char Para1 : 2;
unsigned char state;
unsigned char avail : 1;
}*Env_Alarm_Record;
#include<stdio.h>
int main(void)
{
struct _Record_Struct* pointer = (struct _Record_Struct*)malloc(sizeof(struct _Record_Struct) * MAX_SIZE);
return 0;
}
结果:9
易错点:
1、#define MAX_SIZE A+B 直接替代函数中的位置,非先计算A+B的值再替代。即:
(struct _Record_Struct*)malloc(sizeof(struct _Record_Struct) * 2+3);
2、
struct _Record_Struct
{
unsigned char Env_Alarm_ID : 4;//位段,4bit,占据第一个char(1byte 8bit)的四个bit位()
unsigned char Para1 : 2;//位段,2bit,使用上述第一个char剩余空间大小(2bit)
unsigned char state;//一个完整的字符类型,即1 byte,向内存重新申请一个char类型大小的空间,此为该结构体的第二个char
unsigned char avail : 1;//位段,1bit,使用第三个char的一个bit位。
}*Env_Alarm_Record;
综上,总字节位3.Mallorc计算申请的大小为3*2+3=9
题二:
#include<string.h>
int main()
{
unsigned char puc[4];
struct tagPIM
{
unsigned char ucPim1;
unsigned char ucData0 : 1;
unsigned char ucData1 : 2;
unsigned char ucData2 : 3;
}*pstPimData;
pstPimData = (struct tagPIM*)puc;
memset(puc, 0, 4);
pstPimData->ucPim1 = 2;
pstPimData->ucData0 = 3;
pstPimData->ucData1 = 4;
pstPimData->ucData2 = 5;
printf("%02x %02x %02x %02x\n", puc[0], puc[1], puc[2], puc[3]);
printf("%x %x %x %x\n", puc[0], puc[1], puc[2], puc[3]);
return 0;
}
02 29 00 00 (vs2019)
题三:
在X86下,有下列程序,问输出结果:
#include<stdio.h>
int main()
{
union
{
short k;
char i[2];
}*s, a;
s = &a;
s->i[0] = 0x39;
s->i[1] = 0x38;
printf(" % x\n", a.k);
return 0;
}
0x3839
由于k和i[2]共享同一块内存,k的值将取决于i[0]和i[1]的值以及系统的字节序。
如果系统是小端序,k的值将是0x3839(因为0x38在低位,0x39在高位)。
如果系统是大端序,k的值将是0x3938(因为0x39在低位,0x38在高位)。
二、动态内存
题一:
请问运行Test 函数会有什么样的结果?
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void GetMemory(char* p)
{
p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main(void)
{
Test();
return 0;
}
1、尽管str是指针,但其是指针变量,属于变量的范畴,在函数传参时对该指针变量而言仍为值传递,除非说传递其地址,用一个二级指针来接受,这样才是址传递。
2、因其值传递,临时变量p出了函数被销毁,最终申请的此块动态空间无法访问。此处出现了内存泄漏的问题。
3、因未对str指针做出任何改变,此处还是指针变量还是空指针,出现了对空指针的解引用操作。程序崩溃。
4、此处关于printf的使用为正确用法。
一种正确的写法:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void GetMemory(char** p)
{
*p = (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
free(str);
str = NULL;
}
int main(void)
{
Test();
return 0;
}
题二:
请问运行Test 函数会有什么样的结果?
#include<stdlib.h>
char* GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory();
printf(str);
}
int main(void)
{
Test();
return 0;
}
返回栈空间地址的问题:
1、变量p在GetMemory函数中创建数组并将其地址返回给str指针,GetMemory函数结束后,其内部局部变量销毁,
对应内存空间又还给系统本身,但str得到了地址,指向该地址对应的内存空间,则属于野指针。对其打印会出现未定义行为。
相似错误题:
int f1(void)
{
int x=10;
return &x;
}
ps:返回栈空间的地址是错误的写法,但返回栈空间的变量是没有问题的。
int f2(void)
{
int *ptr;
*ptr =10;
return ptr;//返回指针变量,此处出错是因为野指针的问题。
}
题三:
请问运行Test 函数会有什么样的结果?
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main(void)
{
Test();
return 0;
}
1、瑕疵:没有进行判空操作,当malloc申请失败时,第一次字符拷贝传参可能存在问题
2、问题:free释放动态内存空间,str仍然指向对应地址,只是该地址此可属于系统,后续使用时str为野指针,虽能访问该内存空间,但其操作为非法访问。
文件处理相关
#define和#、##
题一:
解释下述代码输出结果:
#include<stdio.h>
#define PRINT(N,format) printf("the value of "#N" is "format"\n",N)
int main(void)
{
int a = 20;
double b = 93.2;
PRINT(a, "%d");
PRINT(b, "%lf");
return 0;
}
解释下述代码输出结果:
#define RANK(rank,num) rank##num
#include<stdio.h>
int main(void)
{
int studentsrank15 = 15;
printf("%d\n", RANK(studentsrank, 15));
return 0;
}