【ONE·C||代码分析题(二)】

总言

  一些代码分析题,查缺补漏。
  会慢慢学习和补充。

一、关于自定义类型

1)、计算结构体的大小

  涉及知识点:结构体对齐

结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
      对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
      VS中默认的值为8
  3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
    体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

题一:

#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位机
一个double8字节,偏移量0-7;
一个char1字节,偏移量8;
一个int4字节,偏移量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);

2struct _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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值