结构体、共用体与C++基础

1、结构体

结构体是C编程中一种用户自定义的数据类型,类似于Java的JavaBean

//Student 相当于类名
//student和a 可以不定义,表示结构变量,也就Student类型的变量
struct Student
{
char name[50];
int age;
} student,a;
//使用typedef定义
typedef struct{
char name[50];
int age;
} Student;

当结构体需要内存过大,使用动态内存申请。结构体占用字节数和结构体内字段有关,指针占用内存就是4/8字节,因此传指针比传值效率更高。

struct Student *s = (Student*)malloc(sizeof(Student));
memset(s,0,sizeof(Student));
printf("%d\n", s->age);

字节对齐

内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址开始访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序一个接一个地存放,这就是对齐。

字节对齐的问题主要就是针对结构体。

struct MyStruct1
{
short a; //0x30 0x31 0x32 0x33
int b; //0x34 0x35 0x36 0x37
short c; //0x38 0x39 0x3a 0x3b
};
struct MyStruct2
{
short a; //0x2cb028 0x2cb029
short c; //0x2cb02a 0x2cb02b
int b; //0x2cb02c 0x2cb02d 0x2cb02e 0x2cb02f
};
//自然对齐
//1、某个变量存放的起始位置相对于结构的起始位置的偏移量是该变量字节数的整数倍;
//2、结构所占用的总字节数是结构中字节数最长的变量的字节数的整数倍。
// short = 2 补 2
// int = 4
// short = 2 补 2
sizeof(MyStruct1) = 12
// 2个short在一起组成一个 4
sizeof(MyStruct2) = 8
#pragma pack(2) //指定以2字节对齐
struct MyStruct1
{
short a;
int b;
short c;
};
#pragma pack() //取消对齐
//short = 2
//int = 4
//short = 2

合理的利用字节可以有效地节省存储空间

不合理的则会浪费空间、降低效率甚至还会引发错误。(对于部分系统从奇地址访问int、short等数据会导致错误)

自然对齐

  1. 某个变量存放的起始位置相对于结构的起始位置的偏移量是该变量字节数的整数倍;
  2. 结构所占用的总字节数是结构中字节数最长的变量的字节数的整数倍。

2、共用体

在相同的内存位置存储不同的数据类型

共用体占用的内存应足够存储共用体中最大的成员

//占用4字节
union Data
{
int i;
short j;
}
union Data data;
data.i = 1;
//i的数据损坏
data.j = 1.1f;

3、C++

输出

C使用printf向终端输出信息
C++提供了 标准输出流
#include <iostream>
using namespace std;
char *name = "Jay";
int time = 8;
cout << "Jay:" << time << "点," << "天台不见不散"<< endl;

函数符号兼容

第一节课中说到C的大部分代码可以在C++中直接使用,但是仍然有需要注意的地方。

//如果需要在C++中调用C实现的库中的方法
extern "C" //指示编译器这部分代码使用C的方式进行编译而不是C++

众所周知,C是面向过程的语言,没有函数重载。

void func(int x, int y);

对于 func 函数 被C的编译器编译后在函数库中的名字可能为func (无参数符号),而C++编译器则会产生类似funcii之类的名字。

//main.c / main.cpp
int func(int x,int y){}
int main(){return 0;}
gcc main.c -o mainc.o
gcc main.cpp -o maincpp.o nm -A mainc.o
nm -A maincpp.o

main.c

main.cpp

那么这样导致的问题就在于: c的.h头文件中定义了func函数,则.c源文件中实现这个函数符号都是func,然后拿到C++中使用,.h文件中的对应函数符号就被编译成另一种,和库中的符号不匹配,这样就无法正确调用到库中的实现。

因此,对于C库可以:

#ifdef __cplusplus
extern "C"{
#endif
void func(int x,int y);
#ifdef __cplusplus
}
#endif //__cplusplus 是由c++编译器定义的宏,用于表示当前处于c++环境

extern 关键字 可用于变量或者函数之前,表示真实定义在其他文件,编译器遇到此关键字就会去其他模块查找

引用

引用是C++定义的一种新类型

//声明形参为引用
void change(int& i) {
i = 10;
}
int i = 1;
change(i);
printf("%d\n",i); //i == 10

引用和指针是两个东西

引用 :变量名是附加在内存位置中的一个标签,可以设置第二个标签

简单来说 引用变量是一个别名,表示一个变量的另一个名字

注意点

  • 引用相当于是变量的别名(基本数据类型、枚举、结构体、类、指针、数组等,都可以有引用)
  • 对引用做计算,就是对引用所指向的变量做计算
  • 在定义的时候就必须初始化,一旦指向了某个变量,就不可以再改变,“从一而终”
  • 可以利用引用初始化另一个引用,相当于某个变量的多个别名
  • 不存在【引用的引用、指向引用的指针、引用数组】

引用存在的价值之一:比指针更安全、函数返回值可以被赋值

引用的本质

  • 引用的本质就是指针,只是编译器削弱了它的功能,所以引用就是弱化了的指针
  • 一个引用占用一个指针的大小

字符串

C字符串

字符串实际上是使用 NULL字符 '\0' 终止的一维字符数组。

//字符数组 = 字符串
char str1[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
//自动加入\0
char str2[] = "Hello";

字符串操作

函数 描述
strcpy(s1, s2); 复制字符串 s2 到字符串 s1。
strcat(s1, s2); 连接字符串 s2 到字符串 s1 的末尾。
strlen(s1); 返回字符串 s1 的长度。
strcmp(s1, s2); 如果 s1 和 s2 相同,则返回 0;如果 s1 < s2 则返回小于0;如果 s1>s2 则返回大于0
strchr(s1, ch); 返回指向字符串 s1 中字符 ch 的第一次出现的位置的指针。
strstr(s1, s2); 返回指向字符串 s1 中字符串 s2 的第一次出现的位置的指针。

说明:strcmp:两个字符串自左向右逐个字符相比(按ASCII值大小相比较)

C++ string类

C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。

#include <string>
//string 定义在 std命令空间中
usning namespace std;
string str1 = "Hello";
string str2 = "World";
string str3("你好世界");
string str4(str3); // str1拼接str2 组合新的string
string str5 = str1 + str2;
// 在str1后拼接str2 str1改变
str1.append(str2);
//获得c 风格字符串
const char *s1 = str1.c_str();
//字符串长度
str1.size();
//长度是否为0
str1.empty();
......等等

命名空间

namespace 命名空间 相当于package

namespace A{
void a(){}
} 错误 : a();
// :: 域操作符
正确: A::a(); //当然也能够嵌套
namespace A {
namespace B{
void a() {};
}
}
A::B::a(); //还能够使用using 关键字
using namespace A;
using namespace A::B;

当全局变量在局部函数中与其中某个变量重名,那么就可以用::来区分

int i;
int main(){
int i = 10;
printf("i : %d\n",i);
//操作全局变量
::i = 11;
printf("i : %d\n",::i);
}

explicit用法

简介

explicit 只对构造函数有效,用来避免隐式类型转换。且只对仅含有一个参数的类构造函数有效,因为多于两个的时候是不会发生隐式转换的(除非只有一个参数需要赋值,其他的参数有默认值)。

用法

首先定义一个类:

class String{
public:
String (int n); // 分配n个字节空间给字符串
String (const char* p); // 用字符串p的值初始化字符串
}; // 正常初始化的方法:
String s1(10); // 10个字节长度的字符串
String s2("Hello world!"); // s2的初始值为 Hello world // 隐式转换的写法:
String s3 = 10; // 编译通过,分配10个字节长度的字符串
String s4 = 'a'; // 编译通过,分配int('a')个字节长度的字符串
String s5 = "a"; // 编译通过,调用的是String (const char* p)

使用explicit关键字:

class String{
public:
explicit String (int n); // 分配n个字节空间给字符串
String (const char* p); // 用字符串p的值初始化字符串
}; // 此时:
String s3 = 10; // 编译不通过,不允许隐式转换类型
String s4 = 'a'; // 编译不通过,不允许隐式转换类型

使用explicit的好处

当出现下面的场景时,explicit关键字能够在编译阶段给出错误:

class A {
A(int a);
}; int function(A a);

此时,若要调用function(2),则会隐式转换2为A类型,显然不是我们想要的,从而可以使用explicit关键字修饰A 的构造函数避免隐式转换的问题。并且也可以避免String s4 = 'a'; 这种奇怪的赋值语句出现。

内联函数

使用inline修饰函数的声明或者实现,可以使其变成内联函数。

特点

  • 编译器会将函数调用直接展开为函数体代码
  • 可以减少函数调用的开销
  • 会增大代码体积

注意

  • 尽量不要内联超过10行代码的函数
  • 有些函数即使声明为inline,也不一定会被编译器内联,比如递归函数。

什么时候使用内联函数?

  1. 函数代码体积不大。
  2. 频繁调用的函数。

内联函数与宏

对比宏,内联函数多了语法检测和函数特性

  1. 宏容易出错;
  2. 宏不可调试;
  3. 宏无法操作类的私有对象;
  4. 内联函数可以更加深入的优化;



    例如:
#define MUTI(x,y) x*y

inline int muti(int x,int y){
return x * y;
} cout<< MUTI(1+1,2) <<endl;// 3
cout<< muti(1+1,2) <<endl;// 4

C++ 内联函数

C++内联函数的使用

结构体、共用体与C++基础的更多相关文章

  1. C++结构、共用体、枚举

    一.结构 结构是C++OOP的基石.学习有关结构的知识僵尸我们离C++的核心OOP更近. 结构是用户定义的类型,同一个结构可以存储多种类型数据,这使得将一个事物的不同属性构成一个对象成为了可能.另外C ...

  2. 5、数组&字符串&结构体&共用体&枚举

    程序中内存从哪里来 三种内存来源:栈(stack).堆(heap).数据区(.date): 栈(stack) 运行自动分配.自动回收,不需要程序员手工干预: 栈内存可以反复使用: 栈反复使用后,程序不 ...

  3. C语言高级-结构,共用体,文件,链表

    C语言结构 标准声明方式 struct student{        int age;        char sex;    }; 这个可以在main函数中定义:  struct student ...

  4. C语言基础 (11) 结构体 ,共用体 枚举 typedef

    1 课堂回顾 作用域与生命周期 2 static 局部变量 2 打字游戏 3 内存分区代码分析 4 结构体基本操作 (复合类型[自定义类型 #include <stdio.h> #incl ...

  5. 瘋子C语言笔记(结构体/共用体/枚举篇)

    (一)结构体类型 1.简介: 例: struct date { int month; int day; int year; }; struct student { int num; char name ...

  6. C++复合类型(结构,共用体,枚举)

    •结构是用户定义的类型,而结构的声明定义了这种类型的数据属性. 一.关键字struct声明:   定义了一种新类型 struct inflatable{ char name[20];//结构成员 fl ...

  7. C基础知识(8):结构体、共用体、位域

    结构体 数组允许定义可存储相同类型数据项的变量,而结构体是C编程中另一种用户自定义的可用的数据类型,它允许用户可以存储不同类型的数据项. struct 语句的格式如下: struct [structu ...

  8. 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符

    [源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...

  9. C语言------结构体和共用体

    仅供借鉴.仅供借鉴.仅供借鉴(整理了一下大一C语言每个章节的练习题.没得题目.只有程序了) 文章目录 1 .实训名称 2 .实训目的及要求 3.源代码及运行截图 4 .小结 1 .实训名称 实训8:结 ...

  10. 【C语言入门教程】7.4 共用体

    7.4 共用体 共用体又称为联合体,是由不同的数据类型组成的一个整体.与结构体不同的是,共用体每次只能使用其中一个成员.结构体的总长度是结构体所有成员长度之和,共用体的总长度是其中最长一个数据类型的长 ...

随机推荐

  1. 教你用JavaScript实现实时字符计数器

    案例介绍 欢迎来到我的小院,我是霍大侠,恭喜你今天又要进步一点点了!我们来用JavaScript编程实战案例,做一个实时字符计数器.用户在指定位置打字,程序实时显示字符数量. 案例演示 在编辑框内输入 ...

  2. idea启动springboot项目报错java.lang.ClassNotFoundException: com.gctl.bpm.GctlBpmApplication解决方案

    有时候父子工程改造springboot项目时会报错java.lang.ClassNotFoundException: com.gctl.bpm.GctlBpmApplication如下图所示 此时不要 ...

  3. 《ASP.NET Core 与 RESTful API 开发实战》-- (第9章)-- 读书笔记(上)

    第 9 章 测试和文档 9.1 测试 测试是软件生命周期中的一个非常重要的阶段,对于保证软件的可靠性具有极其重要的意义 常见的测试方法有很多,根据不同的维度,可以把测试方法分为不同的类别 从观察结构的 ...

  4. 《ASP.NET Core 与 RESTful API 开发实战》-- (第7章)-- 读书笔记(下)

    第 7 章 高级主题 7.4 HATEOAS 全称 Hypermedia AS The Engine Of Application State,即超媒体作为应用程序状态引擎.它作为 REST 统一界面 ...

  5. Kafka-生产者、broker、消费者的调优参数总结

    生产环境下,为了尽可能提升Kafka的整体吞吐量,可以对Kafka的相关配置参数进行调整,以达到提升整体性能的目的. 本文主要从Kafka的不同组件出发,讲解各组件涉及的配置参数和参数含义. 一.生产 ...

  6. Hadoop-Operation category READ is not supported in state standby 故障解决

    在查询hdfs时或者执行程序向hdfs写入数据时遇到报错:Operation category READ is not supported in state standby 意思是:该主机状态为待机, ...

  7. 多个Nginx进程运行导致配置加载失效问题

    多个Nginx进程运行导致配置加载失效问题 问题描述 在用nginx进行接口代理时,修改配置文件后,重新加载nginx,却发现无论怎么修改配置文件,都无法生效,接口一直无法代理成功.查看了之前做的接口 ...

  8. 了解一下基本的http代理配置

    我们首先用一个简单例子了解一下基本的http代理配置 worker_processes 1; #nginx worker 数量 error_log logs/error.log; #指定错误日志文件路 ...

  9. ABC 304

    T4 在一个平面上有一块面积无限的蛋糕,给出 \(n\) 颗草莓的所在位置和 \(a\,(b)\) 条平行与 \(x\,(y)\) 轴的切刀位置. 切刀会把蛋糕沿 \(x\,(y)\) 轴切开.因此一 ...

  10. C#后端接收前端的参数

    接收参数 1. 直接使用 [FromBody] 特性来告诉 ASP.NET Core 将请求的 JSON 数据反序列化为 实体类 对象 [FromBody] BlogNewsDTO实体类 点击查看代码 ...