c/c++简介

1. 分配内存的方法

面试中比较见问的一个问题。 
注意: 
1. 只有calloc函数会将分配内存初始化为0 
2. newC++独有的,其是运算符,而不是函数。

下面对其分别进行介绍:

1) malloc 函数:

void *malloc(unsigned int size)
  • 1

 在内存的动态分配区域中分配一个长度为size的连续空间,如果分配成功,则返回所分配内存空间的首地址,否则返回NULL,申请的内存不会进行初始化。

2)calloc 函数:

void *calloc(unsigned int num, unsigned int size)
  • 1

 按照所给的数据个数和数据类型所占字节数,分配一个 num * size 连续的空间。calloc申请内存空间后,会自动初始化内存空间为 0,但是malloc不会进行初始化,其内存空间存储的是一些随机数据。

3)realloc 函数:

void *realloc(void *ptr, unsigned int size)
  • 1

增加或减少以前分配区的长度。当增加长度时,可能需要将以前分配区的内容移到另一个足够大的区域,以便在尾端提供增加的存储区,而新增的区域内的初始值不确定。

4)new是动态分配内存的运算符

自动计算需要分配的空间,在分配类类型的内存空间时,同时调用类的构造函数,对内存空间进行初始化,即完成类的初始化工作。动态分配内置类型是否自动初始化取决于变量定义的位置,在函数体外定义的变量都初始化为0,在函数体内定义的内置类型变量都不进行初始化。

2. 存储空间的分布

程序的空间分布通常分为(地址从下到上): 
1. 代码段 
2. 初始化数据段 
3. 未初始化数据段 
4. 堆 
5. 栈

分布如下图所示:(图片来自:C语言内存空间分布详解)

这里写图片描述

堆地址是从下到上增长,栈地址从上到下增长。

一个例题:判断a,b,c,d的存储空间?

int a=0;
class someClass{
   int b;
   static int c;
};
int main(){
   int d=0;
   someClass *p=new someClass();
   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

解析: 
变量a 全局变量 存放在全局变量区 
变量b 类的成员变量 由类的定义决定 在main函数中类A动态分配 因此b在堆区,这里一定要注意,b的存储区域的变化 
变量c 静态成员 静态存储区 
变量d 局部变量 栈区

3. 关于大小端的问题

关于大小端的问题,一定要记住:小端是低地址存低位,而大端是低地址存高位,这点非常的重要。

例题:unsigned int a= 0x1234; unsigned char b=*(unsigned char *)&a; 在32位大端模式处理器上变量b等于()?

解析: 
unsigned int a= 0x1234的32位完全表示是0x00001234, 
由低地址到高地址依次为(假设低地址为0x4000),则其在大端的分布如下:

0x4000        0x4001     0x4002      0x4003
00            00          12          34
  • 1
  • 2

则a的地址&a0x400,char类型占一位,因此b的值为:0x00 
同理如果是小端则值为:0x34

4. 关于指针的问题

如下例题的输出结果是:

void foobar(int a, int *b, int **c)
{
    int *p = &a;
    *p = 101;
    *c = b;
    b = p;
}

int main()
{
    int a = 1;
    int b = 2;
    int c = 3;
    int *p = &c;
    foobar(a, &b, &p);
    printf("a=%d, b=%d, c=%d, *p=%d\n", a, b, c, *p);
    return (0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

解析: 
函数foobar中的a是按值传递,因此在函数中的修改不会引起主函数中的变化。 
函数中b传递的是主函数中b的指针,语句b = p ,其中p指向的是函数foobar内局部变量a的地址,让传递过去的指针换了指向的数据,原来指向的数据(主函数中的b)不会有影响。如果这里是*b = *p那么主函数中的b也要相应变化。 
函数中的c传递的是双重指针,*c = b,也就是让主函数中的p指针指向了主函数中的b的地址 
在函数foobar中对指针的变化没有影响到主函数,只是让双重指针更换了指向而已 
因此答案为:a=1, b=2, c=3, *p=2

5. memmove函数的实现

如果有两段内存重叠,进行memcpy的话则会出现未定义的行为,因此重新写此函数为memmove,用来处理内存重叠式的复制。

#include <iostream>
#include <string.h>
using namespace std;

void* memmove(void *dst,const void *src,size_t n) {
    if (dst == NULL || src == NULL)
        return NULL;
    char* pdst = (char*)dst;
    const char* psrc=(const char*)src;
    if (pdst<psrc) {
        for (size_t i = 0;i<n;i++)
            *(pdst++)=*(psrc++);
    }
    else {
        pdst += n-1;
        psrc += n-1;
        for (size_t i = 0;i<n;i++)
            *(pdst--)=*(psrc--);
    }   
    return dst;
} 
int main(){
    char c1[]="hello,world";
    memmove(c1+3,c1,8);
    cout<<c1<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

上述程序编译执行的结果为:

#include <iostream>
#include <string.h>
using namespace std;

void* memmove(void *dst,const void *src,size_t n) {
    //判断合法性
    if (dst == NULL || src == NULL)
        return NULL;
    char* pdst = (char*)dst;
    const char* psrc=(const char*)src;
    //防止内存重叠的处理
    if (pdst<psrc) {
        for (size_t i = 0;i<n;i++)
            *(pdst++)=*(psrc++);
    }
    else {
        pdst += n-1;
        psrc += n-1;
        for (size_t i = 0;i<n;i++)
            *(pdst--)=*(psrc--);
    }   
    return dst;
} 
int main(){
    char c1[]="hello,world";
    memmove(c1+3,c1,8);
    cout<<c1<<endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

上述程序编译执行的结果为:

helhello,wo
  • 1

6. 关于对static变量的理解

static变量是在实际的编程中常遇到的,在面试中也会常被问到,下面对其进行一些总结。

  1. 静态全局变量:适用于这个全局变量仅在单个文件中进行访问,别的文件无法对其访问时使用,可以降低模块间的耦合度。

  2. 静态局部变量 : 适用于在单个函数内使用,即使在同一个文件中,别的函数也不能对其进行访问,可以降低模块间的耦合度。

  3. 需要注意的一种说法就是,静态全局变量过大,可能会导致堆栈溢出,这句话看似正确,其实不然,因为静态变量放在静态区,不放在堆栈或栈区域,因此其不会导致堆栈溢出的错误。

  4. 如果想声明一个class的专属常量,可以,必须为其声明一个成员,而为了保证期只有一份实体,则将其为static成员: 
    如下所示实现方式 (参考:《effective c++》)

class game {
    static const int num = 5;
    int scores[num];
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值