笔试中遇到的问题总结(一)

来源:互联网 发布:小米商城抢购软件 编辑:程序博客网 时间:2024/05/02 01:37

1.关于结构体的sizeof

a.含有联合体的结构体的sizeof
struct s1
{
    char *
ptr,ch;                  
//有指针变成4+4(为了对齐,char只占1。后补3空)
    union A                         

//后面跟了A定义了一个类型,不占内存,而后面不跟A,是声明了结构体的一个成员,占内存,  
    {
        short a,b;
        unsigned int c:2, d:1;
    };
    struct s1* next;                //指针占4
};

//这样是8+4=12个字节

 

struct s1
{
    char *ptr,ch;                         
    union                                     

//联合体是结构体的成员,占内存,并且最大类型是unsigned int,占4
    {
        short a,b;
        unsigned int c:2, d:1;
     };
     struct s1* next;                       
};//这样是8+4+4=16个字节

 

b.结构体含有结构体的sizeof

struct S1
{
     char c;
     int i;
};
struct S3
{
     char c1;
     S1 s;
     char c2;
};
cout<<sizeof(S3);      //S3=16

        S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。

        c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。


c.带有#pragma pack的sizeof

        它是用来调整结构体对齐方式的,不同编译器名称和用法略有不同,VC6中通过#pragma pack实现,也可以直接修改/Zp编译开关。#pragma pack的基本用法为:#pragma pack( n ),n为字节对齐
数,其取值为1、2、4、8、16,默认是8,如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,

 

 

 

 


2.单链表倒置
在数据结构(严蔚敏版)线性表一节中,有一个逆序创建链表的算法,头插法和这个算法差不多,区别就是逆序创建链表是用给出的数字序列创建链表,而头插法是在原来的链表中从第一个节点开始,每次取出一个节点,然后把这个节点插在头节点后面,直到最后一个节点插到头节点后面,那么原来的链表就倒置了..

下面是C++代码

 

LNode *Reverse(LNode *Head)
{
   LNode *p=Head->next;
   LNode * q=NULL;
   Head->next=NULL;
   while(p)
   {
     q=p->next;   //保存下一个节点的指针

     p->next=Head->next;
     Head->next=p;       //把取出的节点插入到头节点的后面

     p=q;
  }
  return Head;
}

 

 

 

 

 

3.关于a[i]是否和i[a]相等问题

#include "iostream"
using namespace std;
void main()
{
 int a[5]={1,2,3,4,5};
 int i=2;
 printf("%d,%d,%d,%d/n",a[i],*(a+i),*(i+a),i[a]);                //结果是3,3,3,3
}
1.C语言中访问数组元素a[i] 只是简单 替换成 (*((a)+(i)))。
2.编译器只是简单替换,不管a,i什么类型,只要能够进行(*((a)+(i)))运算,就可以进行a[i]运算
3.编译器只是简单替换,只检查(*((a)+(i)))运算是否可行,不会检查i是否越界,i是负数都可以。
4.编译器只是简单替换,(*((a)+(i)))=i[a]完全正确。
5.如果(*((a)+(i)))=(*((i)+(a)) (这应该是成立的),就有a[i]=i[a]。
C语言访问数组元素a[i]只是简单替换成(*((a) + (i)))
并没有规定a是首地址,i是偏移量。 无论a[i]还是i[a],编译器都先转成内部形式 *(a+i)和*(i+a);
对数据访问的时候,*(a+i)的方法是最根本的,最接近硬件上的含义。

 

 

 

 

 

 

4.关于类大小问题
#include "iostream"
using namespace std;

class x
{
public:
 static int count;  
//静态存储空间是系统独立开僻出来的一块空间,和类无关,所以不计算在内。
 int number;
private:
 char c;       
//基类中的私有变量或私有方法会被派生类继承,但是无法访问
 
};
class xy:public x
{
private:
 char y;
public:
 static int type;                
};
void main()
{
 xy test;
 cout<<sizeof(test);           //结果为12,父类中的char c被继承了,占用空间,但是无法使用
}
1.在类中,如果什么都没有,则类占用1个字节,一旦类中有其他的占用空间成员,则这1个字节就不在计算之内,如一个类只有一个int则占用4字节而不是5字节。

2.如果只有成员函数,则还是只占用1个字节,因为类函数不占用空间

3.虚函数因为存在一个虚函数表,需要4个字节(保存在类存储空间开始),数据成员对象如果为指针则为4字节,注意有字节对齐,如果为13字节,则进位到16字节空间。

 

 

 

 

 

5.关于静态成员变量问题
#include<iostream>
using namespace std;
void main()
{
class A
{
int a;
static int b;   //编译出错!!!
charc;
};
cout<<sizeof(A)<<endl;
}

由于静态数据成员的空间分配在全局数据区,因此在程序一开始运行的时候就必须存在,所以静态成员的空间的分配和初始化不可能在函数包括main主函数中 完成,因为函数在程序中被调用的时候才为内部的对象分配空间。

局部类中不允许出现静态数据成员。因为静态数据成员必须在程序运行时候就存在这导致程序无法为局部类中的静态数据成员分配空间。上面的代码是不允许的。


另外:静态成员不能在类定义里边初始化,只能在class body外初始化。
一般形式:    数据类型 类名::静态数据成员名=初值

 

 

 

 

 


6.派生类访问基类的私有变量的方法
1.成员函数
在基类中添加一个成员函数来获取这个成员变量的值。

class yuan
{
 double r;

public:

double GetValueR(){return r;}
};

现在你可以在派生类调用GetValueR来获取R值。但是注意GetValueR()这个函数的访问权限必须是public或者protected,如果它本身也是private那么就跟r一样,在派生类是无法访问的了。


2.友元函数
友元不是成员函数,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。