C 中的结构 - 存储、指针、函数和自引用结构

0. 结构体的内存分配

当声明某种类型的结构变量时,结构成员被分配连续(相邻)的内存位置。

struct student
    {
        char name[20];
        int roll;
        char gender;
        int marks[5];
    } stu1;

此处,内存将分配给name[20]rollgendermarks[5]st1这意味着or的大小struct student将是其成员大小的总和。不是吗?让我们检查。

void main()
{
    printf("Sum of the size of members = %I64d bytes\n", sizeof(stu1.name) 
    + sizeof(stu1.roll) + sizeof(stu1.gender) + sizeof(stu1.marks));
    printf("Using sizeof() operator = %I64d bytes\n",sizeof(stu1));
}

 /* Output */
Sum of the size of members = 45 bytes
Using sizeof() operator = 48 bytes

使用sizeof()运算符给出的3字节数多于成员大小的总和。为什么?这3个字节在内存中在哪里?我们先回答第二个问题。我们可以打印成员的地址来查找这些3字节的地址。

void main()
{
    printf("Address of member name = %d\n", &stu1.name);
    printf("Address of member roll = %d\n", &stu1.roll);
    printf("Address of member gender = %d\n", &stu1.gender);
    printf("Address of member marks = %d\n", &stu1.marks);
}

 /* Output */
Address of member name = 4225408
Address of member roll = 4225428
Address of member gender = 4225432
Address of member marks = 4225436

图片1

我们观察到该数组marks[5]不是从 分配的,而是4225433从 分配的4224536。但为什么?

数据对齐

在研究数据对齐之前,了解处理器如何从内存读取数据非常重要。

处理器在一个周期内读取一个字。对于32 位处理器,该字为4 字节;对于64 位处理器,该字为 8 字节。周期数越少,CPU 的性能越好。

实现这一目标的一种方法是对齐数据。对齐意味着任何大小的基本数据类型的变量t将始终(默认情况下)具有 的倍数的地址t。这本质上是数据对齐。这种情况每次都会发生。

某些数据类型的对齐地址
数据类型大小(以字节为单位)地址
char11的倍数
short22的倍数
int,float44的倍数
doublelong*(指针)88的倍数
long double1616的倍数
结构填充

可能需要在结构的成员之间插入一些额外的字节以对齐数据。这些额外的字节称为填充

在上面的示例中,3字节充当填充。如果没有它们,marks[0] 类型int(地址为 4 的倍数)的基地址将为4225433(不是 4 的倍数)。

您现在大概可以明白为什么不能直接比较结构了。

图片2

结构成员对齐

为了解释这一点,我们将举另一个例子(你会明白为什么)。

struct example
    {
        int i1;
        double d1;
        char c1;

    } example1;

void main()
{
    printf("size = %I64d bytes\n",sizeof(example1));
}

输出会是什么?让我们应用我们所知道的。

i1是4个字节。其后将填充 4 个字节,因为 的地址应能被 8 整除。对于和d1,其后将分别填充 8 和 1 个字节。因此,输出应为 4 + 4 + 8 + 1 = 17 字节。d1c1

图3

 /* Output */
size = 24 bytes

什么?又错了!如何?通过数组struct example,我们可以更好的理解。我们还将打印 的成员的地址example2[0]

void main()
{
    struct example example2[2];
    printf("Address of example2[0].i1 = %d\n", &example2[0].i1);
    printf("Address of example2[0].d1 = %d\n", &example2[0].d1);
    printf("Address of example2[0].c1 = %d\n", &example2[0].c1);

}

 /* Output */
Address of example2[0].i1 = 4225408
Address of example2[0].d1 = 4225416
Address of example2[0].c1 = 4225424

假设 的大小example2[0]是 17 字节。这意味着 的地址example2[1].i1将为4225425。这不可能的,因为 的地址int应该是 4 的倍数。从逻辑上讲, 的可能地址example2[1].i1似乎是4225428,4 的倍数。

这也是错误的。你发现了吗?now的地址example2[1].d1将是 (28 + 4 ( i1) + 3 ( padding)),4225436它不是 8 的倍数。

为了避免这种不对齐,编译器为每个结构引入了对齐。这是通过在最后一个成员之后添加额外的字节来完成的,称为结构成员对齐

图4

在本节开头讨论的示例中,它不是必需的(因此是另一个示例)。

一个简单的记住方法是通过这个规则 -结构地址和结构长度必须是 的倍数t_max。这里,t_max是结构中成员所占用的最大大小

对于struct example,8 字节是 的最大大小d1。因此,结构末尾有 7 个字节的填充,使其大小为 24 个字节。

这两点将帮助您找到任何结构的大小 -
  1. 任何数据类型都将其值存储在其大小倍数的地址中。

  2. 任何结构的大小都是成员所占用的最大字节数的倍数。

尽管我们可以降低 CPU 周期,但仍会浪费大量内存。将填充量减少到可能的最小值的一种方法是按成员变量大小的递减顺序声明成员变量。

如果我们遵循这一点struct example,结构的大小就会减少到 16 个字节。填充从 7 个字节减少到 3 个字节。

图5

struct example
    {
        double d1; 
        int i1;
        char c1;

    } example3;

void main()
{
    printf("size = %I64d bytes\n",sizeof(example3));
}

 /* Output */
size = 16 bytes
结构填料

包装与填充相反。它防止编译器填充并删除未分配的内存。对于 Windows,我们使用该#pragma pack指令,它指定结构成员的打包对齐方式。

#pragma pack(1)

struct example
    {
        double d1; 
        int i1;
        char c1;

    } example4;

void main()
{
    printf("size = %I64d bytes\n",sizeof(example4));
}

 /* Output */
size = 13 bytes

图6

这可确保成员在 1 字节边界上对齐。换句话说,任何数据类型的地址都必须是 1 字节或其大小(以较小者为准)的倍数。

1. 指针

指针作为成员

结构也可以将指针作为成员。

struct student
    {
        char *name;
        int *roll;
        char gender;
        int marks[5];
    };

void main()
{   int alexRoll = 44;
   struct student stu1 = { "Alex", &alexRoll, 'M', { 76, 78, 56, 98, 92 }};
}

使用.(点运算符),我们可以再次访问成员。由于roll现在有 的地址alexRoll,我们将不得不取消引用stu1.roll来获取值(而不是stu1.(*roll))。

printf("Name: %s\n", stu1.name);
   printf("Roll: %d\n", *(stu1.roll));
   printf("Gender: %c\n", stu1.gender);

   for( int i = 0; i < 5; i++)
    printf("Marks in %dth subject: %d\n", i, stu1.marks[i]);

 /* Output */
Name: Alex
Roll: 43
Gender: M
Marks in 0th subject: 76
Marks in 1th subject: 78
Marks in 2th subject: 56
Marks in 3th subject: 98
Marks in 4th subject: 92
结构体指针

与整数指针、数组指针和函数指针一样,我们也有结构体指针或结构体指针。

struct student {
    char name[20];
    int roll;
    char gender;
    int marks[5];
};

struct student stu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};

struct student *ptrStu1 = &stu1;

在这里,我们声明了一个ptrStu1类型为 的指针struct studentstu1我们已将的地址分配给ptrStu1

ptrStu1存储 的基地址stu1,它是结构体第一个成员的基地址。增加 1 将使地址增加sizeof(stu1)字节。

printf("Address of structure = %d\n", ptrStu1);
printf("Adress of member `name` = %d\n", &stu1.name);
printf("Increment by 1 results in %d\n", ptrStu1 + 1);

/* Output */
Address of structure = 6421968
Adress of member 'name' = 6421968
Increment by 1 results in 6422016

我们可以通过两种方式访问stu1​​using的成员。ptrStu1使用 *(间接运算符)或使用->中缀或箭头运算符)。

对于*,我们将继续使用.(点运算符),而对于 ,->我们将不需要点运算符。

printf("Name w.o using ptrStu1 : %s\n", stu1.name);
printf("Name using ptrStu1 and * : %s\n", (*ptrStu1).name);
printf("Name using ptrStu1 and -> : %s\n", ptrStu1->name);

/* Output */
Name without using ptrStu1: Alex
Name using ptrStu1 and *: Alex
Name using ptrStu1 and ->: Alex

同样,我们也可以访问和修改其他成员。请注意,使用时括号是必需的,*因为点运算符 ( .) 的优先级高于*

结构数组

我们可以创建一个类型数组struct student并使用指针来访问元素及其成员。

struct student stu[10];

 /* Pointer to the first element (structure) of the array */
struct student *ptrStu_type1 = stu;

 /* Pointer to an array of 10 struct student */
struct student (*ptrStu_type2)[10] = &stu;

请注意,ptrStu_type1是 一个指向stu[0]while的指针,而ptrStu_type2是一个指向整个数组 10 的指针struct student。加 1 将ptrStu_type1指向stu[1]

我们可以使用ptrStu_type1循环来遍历元素及其成员。

for( int i = 0; i <  10; i++)
printf("%s, %d\n", ( ptrStu_type1 + i)->name, ( ptrStu_type1 + i)->roll);

2. 功能

作为成员发挥作用

函数不能是结构的成员。但是,使用函数指针,我们可以使用(点运算符)调用函数.。但是,不建议这样做。

 struct example
    {
        int i;
        void (*ptrMessage)(int i);


    };

void message(int);

void message(int i)
{
    printf("Hello, I'm a member of a structure. This structure also has an integer with value %d", i);
}

void main()
{
    struct example eg1 = {6, message};
    eg1.ptrMessage(eg1.i);
}

我们在内部声明了两个成员,一个integeri和一个函数指针。函数指针指向一个接受eger 并返回 的函数。ptrMessagestruct exampleintvoid

message就是这样一个函数。我们eg16和初始化message。然后我们使用和 pass.来调用该函数。ptrMessageeg1.i

结构作为函数参数

与变量一样,我们可以将单个结构成员作为参数传递。

#include <stdio.h>

struct student {
    char name[20];
    int roll;
    char gender;
    int marks[5];
};

void display(char a[], int b, char c, int marks[])
{
    printf("Name: %s\n", a);
    printf("Roll: %d\n", b);
    printf("Gender: %c\n", c);

    for(int i = 0; i < 5; i++)
        printf("Marks in %dth subject: %d\n",i,marks[i]);
}
void main()
{
    struct student stu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    display(stu1.name, stu1.roll, stu1.gender, stu1.marks);
}

 /* Output */
Name: Alex
Roll: 43
Gender: M
Marks in 0th subject: 76
Marks in 1th subject: 98
Marks in 2th subject: 68
Marks in 3th subject: 87
Marks in 4th subject: 93

请注意,该结构是在最顶部的struct student外部声明的。main()这是为了确保它在全球范围内可用并且display()可以使用。

如果该结构体在内部定义main(),其范围将被限制为main().

当结构成员数量很大时,传递结构成员的效率不高。然后结构变量可以传递给函数。

void display(struct student a)
{
    printf("Name: %s\n", a.name);
    printf("Roll: %d\n", a.roll);
    printf("Gender: %c\n", a.gender);

    for(int i = 0; i < 5; i++)
        printf("Marks in %dth subject: %d\n",i,a.marks[i]);
}
void main()
{
    struct student stu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    display(stu1);
}

如果结构的大小很大,那么传递它的副本不会非常有效。我们可以将结构指针传递给函数。在这种情况下,结构的地址作为实际参数传递。

void display(struct student *p)
{
    printf("Name: %s\n", p->name);
    printf("Roll: %d\n", p->roll);
    printf("Gender: %c\n", p->gender);

    for(int i = 0; i < 5; i++)
        printf("Marks in %dth subject: %d\n",i,p->marks[i]);
}
void main()
{
    struct student stu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    struct student *ptrStu1 = &stu1;
    display(ptrStu1);
}

将结构数组传递给函数类似于将任何类型的数组传递给函数。数组的名称,即结构体数组的基地址,被传递给函数。

void display(struct student *p)
{   
    for( int j = 0; j < 10; j++)
   {
       printf("Name: %s\n", (p+j)->name);
        printf("Roll: %d\n", (p+j)->roll);
        printf("Gender: %c\n", (p+j)->gender);

        for(int i = 0; i < 5; i++)
        printf("Marks in %dth subject: %d\n",i,(p+j)->marks[i]);
   }
}

void main()
{
    struct student stu1[10];
    display(stu1);
}
结构作为函数返回

我们可以返回一个结构变量,就像任何其他变量一样。

#include <stdio.h>

struct student {
    char name[20];
    int roll;
    char gender;
    int marks[5];
};


struct student increaseBy5(struct student p)
{
    for( int i =0; i < 5; i++)
        if(p.marks[i] + 5 <= 100)
           {
               p.marks[i]+=5;
           }
    return p;
}

void main()
{
    struct student stu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    stu1 = increaseBy5(stu1);

    printf("Name: %s\n", stu1.name);
    printf("Roll: %d\n", stu1.roll);
    printf("Gender: %c\n", stu1.gender);

    for(int i = 0; i < 5; i++)
        printf("Marks in %dth subject: %d\n",i,stu1.marks[i]);
}

 /* Output */
Name: Alex
Roll: 43
Gender: M
Marks in 0th subject: 81
Marks in 1th subject: 98
Marks in 2th subject: 73
Marks in 3th subject: 92
Marks in 4th subject: 98

该函数increaseBy5()对加分后分数小于或等于 100 的科目加 5 分。注意,返回类型是 类型的结构体变量struct student

返回结构成员时,返回类型必须是该成员的类型。

结构体指针也可以由函数返回。

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

struct rectangle {
    int length;
    int breadth;
};

struct rectangle* function(int length, int breadth)
{
    struct rectangle *p  = (struct rectangle *)malloc(sizeof(struct rectangle));
     p->length = length;
     p->breadth = breadth;
    return p;
}

void main()
{
    struct rectangle *rectangle1 = function(5,4);
    printf("Length of rectangle = %d units\n", rectangle1->length);
    printf("Breadth of rectangle = %d units\n", rectangle1->breadth);
    printf("Area of rectangle = %d square units\n", rectangle1->length * rectangle1->breadth);
}

 /* Output */
Length of rectangle = 5 units
Breadth of rectangle = 4 units
Area of rectangle = 20 square units

struct rectangle请注意,我们已经使用动态分配了 size 的内存malloc()。由于它返回一个void指针,我们必须将其类型转换struct rectangle指针。

3. 自指结构

我们讨论过指针也可以是结构的成员。如果指针是结构体指针怎么办?结构体指针可以与结构体类型相同,也可以不同

自引用结构是那些具有与其成员相同类型的结构指针的结构。

struct student {
    char name[20];
    int roll;
    char gender;
    int marks[5];
    struct student *next;
};

这是一个自引用结构,其中nextstruct student类型结构指针。我们现在将创建两个结构变量stu1stu2用值初始化它们。然后我们将把 的地址存储stu2在 的next成员中stu1

void main()
{
    struct student stu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}, NULL};
    struct student stu2 = { "Max", 33, 'M', {87, 84, 82, 96, 78}, NULL};
    stu1.next = &stu2;
}

图7

stu2我们现在可以访问使用stu1和的成员next

void main()
{
    printf("Name: %s\n", stu1.next->name);
    printf("Roll: %d\n", stu1.next->roll);
    printf("Gender: %c\n", stu1.next->gender);

    for(int i = 0; i < 5; i++)
        printf("Marks in %dth subject: %d\n",i,stu1.next->marks[i]);
}

 /* Output */
Name: Max
Roll: 33
Gender: M
Marks in 0th subject: 87
Marks in 1th subject: 84
Marks in 2th subject: 82
Marks in 3th subject: 96
Marks in 4th subject: 78

假设我们想要在 后添加一个不同的结构体变量stu1,即在之间插入另一个结构体变量stu1stu2。这很容易做到。

void main()
{
    struct student stu3 = { "Gasly", 23, 'M', {83, 64, 88, 79, 91}, NULL};
    st1.next = &stu3;
    stu3.next = &stu2;
}

图8

现在stu1.next存储 的地址stu3。并stu3.next有地址stu2。我们现在可以使用访问所有三个结构stu1

  printf("Roll Of %s: %d\n", stu1.next->name, stu1.next->roll);
  printf("Gender Of %s: %c\n", stu1.next->next->name, stu1.next->next->gender);

 /* Output */
Roll Of Gasly: 23
Gender Of Max: M

stu1请注意我们如何使用结构指针在,stu3和之间形成链接stu2我们在这里讨论的内容构成了链表的起点。

自引用结构在创建数据结构(例如链表堆栈队列等)时非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/206038.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

11-30 JavaWeb

修改与删除操作 防止空指针异常 localhost:8080 -> 分页查询 修改流程&#xff1a;(先查后改(两个servlet)) 修改&#xff1a; 传用户id(用户id怎么得到 -> 循环一次得到一个user 对象 user对象里用user.getId()得到用户id) UpdateUserQueryServlet.java &#xff08;…

「Verilog学习笔记」状态机-重叠序列检测

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 读入数据移位寄存&#xff0c;寄存后的数据与序列数做对比&#xff0c;相等则flag为1&#xff0c;不等则为0 timescale 1ns/1nsmodule sequence_test2(input wire clk ,in…

计网Lesson5 - MAC 地址与 ARP

文章目录 M A C MAC MAC 地址1. M A C MAC MAC 地址的格式 2. M A C MAC MAC 地址的获取3. A R P ARP ARP 协议4. A R P ARP ARP 缓存5. R A R P RARP RARP M A C MAC MAC 地址 1. M A C MAC MAC 地址的格式 每个网卡都有一个 6 6 6 字节的 M A C MAC MAC 地址 M A C…

最大公约数的C语言实现xdoj31

时间限制: 1 S 内存限制: 1000 Kb 问题描述: 最大公约数&#xff08;GCD&#xff09;指某几个整数共有因子中最大的一个&#xff0c;最大公约数具有如下性质&#xff0c; gcd(a,0)a gcd(a,1)1 因此当两个数中有一个为0时&#xff0c;gcd是不为0的那个整数&#xff…

ios 逆向分分析,某业帮逆向算法(一)

用到工具: 爱思助手CrackerXL(砸壳软件)越狱手机ida反汇编软件分析login 的sign 签名算法中自己写算法 已知我们32位,我们不妨猜测是md5 ,那我们试图使用CC_MD5 ,这个是ios 中的标准库, 我们使用frida-trace 注入hook一下,看看有没有 经过 是经过了这个函数,密码也是…

计算机服务器中了_locked勒索病毒如何处理,_locked勒索病毒解密数据恢复

网络技术的不断发展&#xff0c;给企业的生产生活提供了极大便利&#xff0c;越来越多的企业走向数字化办公时代&#xff0c;但网络的发展也为网络安全埋下隐患&#xff0c;网络安全威胁不断增加。近期&#xff0c;云天数据恢复中心陆续接到很多企业的求助&#xff0c;企业的计…

FO-like Transformation Oracle Cloning

参考文献&#xff1a; [RS91] Rackoff C, Simon D R. Non-interactive zero-knowledge proof of knowledge and chosen ciphertext attack[C]//Annual international cryptology conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 1991: 433-444.[BR93] Bellare M…

网狐类源码游戏配置数据库数据(一键配置网狐数据库)

网狐类源码游戏配置数据库数据&#xff08;一键配置网狐数据库&#xff09; 一般拿到网狐的源码或组件&#xff0c;需要先附加或配置数据库&#xff0c;以下为全部需要更改数据的地方&#xff0c;这里以荣耀系列版本数据库为例&#xff1a; 1. 数据库设置 [RYPlatformDB].…

appium :输入框控件为android.view.View 时输入内容(如:验证码、密码输入框)

问题背景 输入密码的组件信息为&#xff1a;<android.view.View resource-id“com.qq.ac.android:id/pwd_input”> 由于输入框控件是android.view.View&#xff0c;不是android.widget.EditText&#xff0c;所以只能点击&#xff0c;而启动appium后&#xff0c;会将输入…

华为全屋智能5.0,无为而“智”

在赖特西塔里埃森混凝土墙的中心壁龛里&#xff0c;一块铜牌上刻着一些英文&#xff0c;意思是“建筑的意义不是屋顶和墙&#xff0c;而是人们生活于其中的空间”。 这句话&#xff0c;取自老子《道德经》中的“凿户牖以为室&#xff0c;当其无&#xff0c;有室之用”。 《理想…

知乎禁止转载的回答怎么复制做笔记?

问题 对于“禁止转载”的回答&#xff0c;右键复制是不行的&#xff0c;ctrl-c也不行&#xff0c;粘贴之后都是当前回答的标题。稍微看了代码&#xff0c;应该是对copy事件进行了处理。不过这样真的有用吗&#xff0c;真是防君子不防小人&#xff0c;只是给收集资料增加了许多…

osgFX扩展库-刻线特效、立方图镜面高光特效(2)

刻线特效 刻线特效(osgFX::Scribe)是一个双通道的特效&#xff0c;第一个通道以通常的方式渲染图形&#xff0c;第二个通道使用线框模式。用户设置好光照和材质之后&#xff0c;即可使用指定的颜色进行渲染。这个特效使用了PolygonOffset渲染属性类来避免多边形斑驳(Z-fighting…

【多传感器融合】BEVFusion: 激光雷达和视觉融合框架 NeurIPS 2022

前言 BEVFusion其实有两篇&#xff0c; 【1】BEVFusion: A Simple and Robust LiDAR-Camera Fusion Framework. NeurIPS 2022 | 北大&阿里提出 【2】BEVFusion: Multi-Task Multi-Sensor Fusion with Unified Bird’s-Eye View Representation 2022 | MIT提出 本文先分…

Constraintlayout

goneMargin 约束的View隐藏时的margin 约束链风格 chainStyle 权重 bias 设置宽高比 w,h 百分比 GuideLine 基线 上下的间距 Group 指定一系列View进行绑定进行操作 通过init加载 然后setIds进行绑定 然后通过group进行操作 Layer 设置动画 Barrier Flow

【猜数字游戏】用wxPython实现:基本的游戏框架 + 简单的图形用户界面

【猜数字游戏】 写在最前面猜数字游戏 实现【猜数字游戏】安装wxPython全部代码代码解析1. 初始化界面2. 生成随机数3. 处理猜测4. 特殊功能5. 分数计算 游戏小程序呈现结语 写在最前面 看到了一个比较有意思的问题 https://ask.csdn.net/questions/8038039 猜数字游戏 在这…

【模电】放大电路的性能指标

放大电路的性能指标 放大倍数输入电阻输出电阻通频带非线性失真系数最大不失真输出电压最大输出功率与效率 下图所示为放大电路的示意图。 对于信号而言&#xff0c;任何一个放大电路均可看成一个两端口网络。左边为输入端口&#xff0c;当内阻为 R s R\tiny s Rs的正弦波信号…

【Java 并发编程】进程线程、lock、设计模式、线程池...

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; Java | 从入门到入坟 Java 并发编程 并发编程多线程的入门类和接口线程组和线程优先级线程的状态及主要转化方法线程间的通信重排序和 happens-beforevolatilesynchronized 与锁CAS 与原子操作AQS计划任务Stream 并行计…

uc_09_创建新进程 exec() system()

1 什么是创建新进程(夺舍) 在前面文章中&#xff0c;我们学习了fork()函数用来创建子进程。 子进程是父进程的副本&#xff0c;复制父进程除代码段以外的其他数据&#xff0c;代码段数据和父进程共享。 子进程的PID与父进程不同&#xff1a; 而创建新进程则不同。 与fork()不同…

TZOJ 1387 人见人爱A+B

答案&#xff1a; #include <stdio.h> void time(int ah, int am, int as, int bh, int bm, int bs, int* sum_h, int* sum_m, int* sum_s) //不需要返回值所以定义void函数&#xff0c;前面6个为输入&#xff0c;然后用指针存给后面三个 {*sum_s (as bs) % 60; …

达梦数据库安装(DM8)新版 windows11下安装及超详细使用教程

达梦数据库安装&#xff08;DM8&#xff09;新版 windows11下安装及超详细使用教程 新电脑安装重新写了一下 注意看一下踩坑部分 文章目录 1.DM 数据库安装1.1 windows11安装前准备1.1.0 安装环境要求1.1.1 检查系统信息1.1.2 检查系统内存1.1.3 检查存储空间 1.2 官网下载免…
最新文章