C/C++笔试题笔记

目录

一、#运算符

二、## 运算符 预处理粘合剂

三、 结构体中使用字符数组还是字符指针

四、内存越界

五、free()和delete是如何处理动态开辟内存的指针的?

六、Liunx内核源码分析

七、64和32位Liunx系统字节对齐问题

八、const指针与指向const的指针


目录

一、#运算符

二、## 运算符 预处理粘合剂

三、 结构体中使用字符数组还是字符指针

四、内存越界

五、free()和delete是如何处理动态开辟内存的指针的?


一、#运算符

在字符串中包含宏参数;#把文本符号转化为可以替换的语言标识

字符串化;"#x"-->把宏参数转换成字符串;

#include <stdio.h>
//#define SQUARE(x) (printf("x square is %d",(x)*(x)))
//在字符串中包含宏参数;#把文本符号转化为可以替换的语言标识符
#define SQUARE(x) (printf(""#x" square is %d\n",(x)*(x)))

void main(void)
{
    SQUARE(4+2);
    SQUARE(4);
    return 0;
}

输出结果:

4+2 square is 36
4 square is 16

二、## 运算符 预处理粘合剂

## 用它把两个语言符号替换成一个语言符号

#include <stdio.h>

#define XNAME(n)     xn   //有两个语言符号x、n;

int main(void)
{
    int XNAME(1) = 10;    //x1 = 10       这里x和n并没有合并成xn语言符号
    printf("%d\n",x1);
    return 0;
}

输出结果:报错;xn并没有没有替换成x1。

#include <stdio.h>

//#define XNAME(n)     xn   //有两个语言符号x、n;
#define XNAME(n)     x##n   //有两个语言符号x、n;


int main(void)
{
    int XNAME(1) = 10;    //x1 = 10   
    printf("%d\n",x1);
    return 0;
}

输出结果10

三、 结构体中使用字符数组还是字符指针

#include <stdio.h>
#include <string.h>

#define SIZE 80

struct std
{
    unsigned int id;
    //unsigned *name;//四个字节,只能放一个地址,指针未初始化随机分配,此地址可能不允许被访问;
    unsigned name[SIZE];
    unsigned int age;

}per;

int main(void)
{
    per.id = 0001;
    strcpy(per.name,"ABCD"); 
//per.name = "ABCD";//把"ABCD"此字符串所在的地址赋给了指针变量,此地址是在静态内存当中不允许
//被修改
    per.age = 10;

    printf("%s\n",per.name);

}

总结:在结构体中存放字符串时,优先考虑使用数组,提前开辟大空间。

四、内存越界

char *p1 = "ABCDEFG";
char *p2 = (char *)malloc(strlen(p1));
strcpy(p2,p1);
//malloc()开辟一片以字节为单位的动态内存空间,返回值为void型。
//设想:p2指向了新开辟的大小为strlen(p1)的内存空间,再把p1里的字符串复制给p2
//此处 strlen(p1) = 6,不包含"\0"。
//strcpy:包含"\0"空字符一定拷贝的。
//printf():在打印时,直到遇到"\0"结束。

在上段代码中,在开辟内存空间时,少了一位。

五、free()和delete是如何处理动态开辟内存的指针的?

free():只是把指针指向的内存释放掉了,指针仍然存在。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    char *p = (char *)malloc(100);//开辟一块100字节的内存空间。
    strcpy(p,"ABCABC");
    printf("p = %s\n",p);

    free(p);//p仍然存在,可以操作

    if(p != NULL)
    {
        strcpy(p,"hello world");
        printf("p = %s\n",p);
    }
    
    return 0;
}

delete:删除掉,

#icnlude <iostream>
#include <cstring>

using namespace std;

int main(void)
{
    char *p = new char[100];
    strcpy(p,"ABCABC");
    cout << "p = "<< p << endl;

    delete []p;
    
    if(p != 0)
    {
        strcpy(p,"hello world!");
        cout << "p = "<< p << endl;
    }
    
    return 0;
}

总结:free delete只是释放了内存空间,此时p就是一个悬空指针,为指向任何内存空间。尽量不要在使用,在释放掉内存之后,可以再把指针指向一个空地址,p = NULL;

六、Liunx内核源码分析

#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)

1.(TYPE *)0:将0强制类型转换为TYPE类型指针,p = (TYPE *)0

2.((TYPE *)0)->MEMBER ----> p->MEMBER         访问MEMBER成员变量

3.&((TYPE *)0)->MEMBER        取出MEMBER成员变量的地址

4.(size_t)&((TYPE *)0)->MEMBER         将MEMBER成员变量的地址转换程size_t类型的数据

总结:求MEMBER成员变量在TYPE 中的偏移量。

七、64和32位Liunx系统字节对齐问题

#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)

typedef struct s
{
    union    //联合体公用一块内存
    {
        int a;    //4个字节
        char str[10];    //10个字节
    }
    struct s* next;
}S;

int main(void)
{
    printf("%ld\n",offsetof(S,next));    //%ld size_t
    return 0;
}

理论输出结果为10,但是实际结果为16.

64位操作系统,最小操作内存空间大小位8字节,所以至少16个字节才可以存放下此联合体。

32位操作系统,最小可操作内存空间大小为4字节,所以至少需要12字节才可存放此联合体。

#pragma pack(2)        //当前两字节对齐

八、const指针与指向const的指针

const 关键字的作用:

1.const定义一个常量,这个常量在定义是必须初始化,否则就没有机会了

2.const定义的常量,并不是真正意义上的常量,本质上还是变量,可以用指针的方式修改他的值。

3.const和指针的用法

        const int *pt;

        int const *pt;        //两者相同,都表示pt可以指向任意对象,但是不能通过pt修改指针修改指

向的对象。

        int *const pt;        //pt指针不能指向其他位置,但是可以通过pt指针修改内容。

4.const 修饰形参

#include <stdio.h>

int main(void)
{
    const int i = 10;

    const int *pt = &i;
    *pt = 20;    //会报错

    printf("i = %d\n",i);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值