【C语言】结构体——我就是秩序的创建者!(结构体数组、结构体指针、嵌套、匿名、字面量、伸缩型数组、链式结构)

  • 一、结构体基础
    • 1.1 声明和定义
    • 1.1 初始化和赋值
    • 1.3 访问结构体成员
  • 二、结构体数组
    • 2.1 定义和初始化
    • 2.2 访问
  • 三、结构体的嵌套
  • 五、指向结构体的指针
  • 六、向函数传递结构体
    • 6.1 只传递结构体成员
    • 6.2 传递结构体指针
    • 6.3 传递结构体
  • 七、结构体的其他特性——不容小觑
    • 7.1 结构体的大小问题
    • 7.2 成员变量是字符数据和字符指针
      • 7.21 注意事项
      • 7.22 指针型成员变量的正确使用方式
    • 7.3 结构体的复合字面量——临时结构体
    • 7.4 匿名结构体
    • 7.5 伸缩型数组成员
    • 7.6 应用——结构体与文件、数据库
  • 八、结构体的应用——链式结构

一、结构体基础

1.1 声明和定义

结构体(也有称:结构)是一种集合,它里面包含了多个变量或数组,它们的类型可以相同,也可以不同,每个这样的变量或数组都称为结构体的成员(Member),使用结构体,有助于提高数据的表示能力。

如:

struct name{char first[10];char last[10];int age;
};

声明了一个结构体name,现在并没有创建实际的数据对象,编译器没有分配存储空间,只是声明了该对象由什么组成,即模板

上述结构中,有3个结构体成员,结构体成员可以使任何数据类型:基本数据类型,结构体,结构体指针等。

可以用struct name来定义来定义变量,变量的结构和模板一样,相当于使用int来定义一个int型变量。

struct name Jay;

这样就定义了一个结构体变量。编译器为他分配24字节的空间。

当然也可以声明多个结构体变量,以及指向struct name类型结构的指针:

struct name Jay,David,*Jolin;

通常我们使用typedef对结构体类型重命名:

typedef struct {char first[10];char last[10];int age;
}Name;

现在:Name就相当于前面的struct name,这样是的代码更简洁,可读性更强。

1.1 初始化和赋值

(1)初始化

定义结构体变量的同时可以进行初始化,使用花括号括起来的初始化列表进初始化,各项之间逗号隔开,各项按照其初始化规则进行初始化,比如成员变量是一个数组,该变量应该按照数组初始化方式初始化。

Name Jay = {"Jay","Chou",18};

结构体变量也支持初始化器,即指定某几项进行初始化:

Name Jay = {.age = 18};   //只初始化age成员变量

(2)赋值

只有初始化的时候可以使用花括号进行整体复制,后面需要单独对成员进行复制。或者使用结构体字面量(后面将)。

结构体变量之间支持直接赋值,这和数组不同。

    //struct name Jay={"Jay","Chou",18};// Name Jay = {"Jay","Chou",18};//Name Jay = {.age=18};Name Jay;//Jay = {"Jay","Chou",18};  //这是错误写法//Jay = (Name){"Jay","Chou",18};   //正确Name David = {"David","Tao",18};Jay =David;Jay.age = 888;

1.3 访问结构体成员

使用结构体成员运算符:. 来访问结构中的成员,访问成员变量的元素则由成员类型决定,如数组使用下标访问各个元素。

如访问结构体变量的成员age:

Jay.age

本小节测试代码:

#include <stdio.h>typedef struct{char first[10];char last[10];int age;
}Name;int main(){//struct name Jay={"Jay","Chou",18};// Name Jay = {"Jay","Chou",18};//Name Jay = {.age=18};Name Jay;//Jay = {"Jay","Chou",18};  //这是错误写法//Jay = (Name){"Jay","Chou",18};Name David = {"David","Tao",18};Jay =David;Jay.age = 888;printf("%s %s,%d\n",Jay.last,Jay.first,Jay.age);return 0;
}

输出:
在这里插入图片描述


本小节的内容仅适用于结构体变量成员中不含指针的情况。

二、结构体数组

结构体数组:数组中每个元素都是结构体。当素组每个元素都有多个属性时,就可以使用结构体数组,比如用它来记录一个班每个学生的信息。

2.1 定义和初始化

定义并初始化一个结构体数组,包含2个元素,每个元素都是结构体:

    Name singer[2]={{"Jay","Chou",18},{"David","Tao",888},};

2.2 访问

访问数组元素使用下标,访问结构体变量使用.

比如第一个数组元素的age成员

singer[0].age

本小节代码:

#include <stdio.h>typedef struct{char first[10];char last[10];int age;
}Name;int main(){Name singer[2]={{"Jay","Chou",18},{"David","Tao",888},};for(int i=0;i<2;i++)printf("%s %s,%d\n",singer[i].first,singer[i].last,singer[i].age);return 0;
}

输出:
在这里插入图片描述

三、结构体的嵌套

即结构体的成员变量也可以是结构体。

例:

#include <stdio.h>typedef struct{char early_aalbum [2][20];
}Album;typedef struct{char first[10];char last[10];int age;Album album;
}Name;int main(){Name singer[2]={{"Jay","Chou",18,{"《Jay》","《Fantasy》"}},{"David","Tao",888,{"《David Tao》","《I'm OK》"}},};for(int i=0;i<2;i++)printf("%s %s,  %d,  Album:  %s, %s\n", singer[i].first,singer[i].last,singer[i].age,singer[i].album.early_aalbum[0],singer[i].album.early_aalbum[1]);return 0;
}

输出:
在这里插入图片描述

  • 结构体的大小等于各成员大小之和;
  • 上面的Name结构体大小时64字节,则singer这个结构体数组大小时128字节;
  • 结构体大小也有可能大于成员大小之和,因为有的系统将成员放在偶数地址上。

五、指向结构体的指针

(1)声明:

Album *p;

指针p现在可以指向任意一个Album类型的结构体。如:

p = &singer[0].album

p指向了数组singer的第一个元素的成员album,该成员是个Album类型的结构体。

注意:结构体变量名不是结构体的地址。

(2)用指针访问成员

使用箭头:->

下面3种写法等价:

    printf("His first albul is: %s\n",p->early_aalbum[0]);printf("His first albul is: %s\n",singer[0].album.early_aalbum[0]);printf("His first albul is: %s\n",(*p).early_aalbum[0]);

六、向函数传递结构体

结构体:

typedef struct{int num1;int num2;
}Num;...Num num = {888,999};
Num *p =&num;

6.1 只传递结构体成员

// 只传递结构体成员
int func_1(int a,int b){return a>b? a:b;
}...func(num.num1,num.num2);

6.2 传递结构体指针

// 传递结构体指针
int func_2(Num *tmp){return tmp->num1 > tmp->num2? tmp->num1 : tmp->num2;
}...
func(p);

6.3 传递结构体

// 传递结构体 
int func_3(Num tmp){return tmp.num1 > tmp.num2? tmp.num1 : tmp.num2;
}...
func(num);

完整实例:

#include <stdio.h>typedef struct{int num1;int num2;
}Num;// 只传递结构体成员
int func_1(int a,int b){return a>b? a:b;
}// 传递结构体指针
int func_2(const Num *tmp){return tmp->num1 > tmp->num2? tmp->num1 : tmp->num2;
}// 传递结构体 
int func_3(const Num tmp){return tmp.num1 > tmp.num2? tmp.num1 : tmp.num2;
}int main(){Num num = {888,999};Num *p = &num;printf("%d\n",func_1(num.num1,num.num2));printf("%d\n",func_2(p));printf("%d\n",func_3(num));return 0;
}

输出:

root@CQUPTLEI:~/Linux_test/LinuxC_learn/c_struct# gcc -Wall -o test transport.c
root@CQUPTLEI:~/Linux_test/LinuxC_learn/c_struct# ./test
999
999
999

注:

  1. 使用const防止结构体被篡改;
  2. 传递结构体的优缺点:
    • 简单直接;
    • 内存开销大,效率低:这种方式会在栈上创建一个结构体的副本,以保证原始结构体不变。
  3. 使用结构体指针的优缺点:
    • 节省内存和时间;
    • 可修改原始结构体(如果你想避免,可以使用const);
    • 可能会增加代码复杂度;
    • 要注意空指针的问题。

七、结构体的其他特性——不容小觑

7.1 结构体的大小问题

结构体的大小是由其成员变量的类型对齐方式决定的。

  1. 成员变量的大小:结构体的大小受到其成员变量大小的影响。基本数据类型的大小在大多数编译器中是固定的,例如int通常是4个字节。对于数组或指针等类型,大小取决于其元素类型的大小。结构体的成员变量按照其定义的顺序依次存储在内存中。

  2. 对齐方式:为了提高内存访问的效率,结构体的成员变量通常会按照一定的对齐方式进行排列。对齐方式可以通过编译器的默认规则或指令进行控制。常见的对齐规则是按照成员变量的大小将其放置在内存地址能被整除的位置上。例如,如果一个结构体成员变量的大小为4字节,那么它通常会被放置在内存地址是4的倍数的位置上。

  3. 填充字节:为了满足对齐要求,有时候编译器会在结构体的成员变量之间插入额外的填充字节,以保证对齐。填充字节不属于结构体成员变量,但会影响结构体的大小。填充字节的大小取决于编译器和对齐方式。

  4. 结构体大小计算:结构体的大小可以使用sizeof运算符来计算。sizeof返回结构体所占用的字节数,包括成员变量和填充字节。注意,sizeof的计算结果可能会受到编译器和编译选项的影响,因此在跨平台或多编译器环境中,可能需要注意结构体大小的一致性。

需要注意的是,结构体的大小可能因编译器、对齐规则和平台而异。为了确保结构体的大小和布局符合预期,可以使用编译器提供的对齐指令或预处理指令进行控制。例如,#pragma pack指令可以在某些编译器中用来指定结构体的对齐方式。

例:

typedef struct{int num1;int num2;
}Num;
...
Num num = {888,999};
...
printf("%zd\n",sizeof(num));

在Ubuntu上使用gcc编译,结果是8字节。

7.2 成员变量是字符数据和字符指针

7.21 注意事项

当结构体的成员是字符数组或字符指针的时候,要注意:

  1. 字符数据(字符数组):

    • 确保字符数组有足够的空间来存储所需的字符串。如果字符串长度超过数组大小,可能会导致缓冲区溢出和未定义行为。
    • 使用字符串处理函数时,确保输入的字符串以 null 终止(即以\0结尾),以避免在处理字符串时出现错误。
    • 考虑字符数组的长度和预留空间,以防止内存浪费或不足。
  2. 字符指针:

    • 确保字符指针指向有效的内存区域,且不为 null。使用字符指针之前,应该先进行空指针检查,以避免出现悬空指针错误。
    • 注意字符指针的生命周期和内存管理。确保字符指针指向的内存区域在使用期间有效,并在不再需要时正确释放内存,以避免内存泄漏。
  3. 字符串操作和安全性:

    • 当对字符数据或字符指针进行字符串操作时,务必确保输入的字符串是正确的、合法的,并进行适当的输入验证和边界检查,以避免缓冲区溢出和安全漏洞。
    • 使用安全的字符串处理函数,如strncpy()strncat()等,以指定最大操作长度,防止缓冲区溢出。
  4. 字符编码和字符集:

    • 理解所使用的字符编码和字符集。不同的编码和字符集可能影响字符数据的表示方式和处理方法。确保正确地处理和处理不同字符编码和字符集的情况。
  5. 内存对齐和填充字节:

    • 注意结构体中字符数据和字符指针的对齐方式和填充字节,特别是在涉及跨平台或与外部环境交互的情况下。可以使用编译器指令或预处理指令进行控制。

例:

  1. 成员变量是一个指针,在赋值的时候让它指向一个字符串。这时,计算结构的大小时应该使用指针变量本身的大小,而不是它指向的字符串的大小,因为字符串并不存储在结构体内部,结构体成员只存储了这个指针变量。(在64位系统中,一个指针变量的大小是8字节)
  2. 成员变量是指针,没有初始化或其他处理就使用,这会有潜在风险,或许你的程序看起来没什么问题。

下面的代码定义了一个Test类型的结构体变量var,它有一个指针类型成员,初始化的时候将它指向一个字符串常量。

#include <stdio.h>typedef struct{int a;int b;char arr[10];char *p;
}Test;int main(){char str[20]="Hello,C language.";Test var = {11,22,{[5]='B'},str};puts("The content of var:");printf("a: %d\nb: %d\narr: ",var.a,var.b);for(int i=0;i<10;i++)printf("%c ",var.arr[i]);printf("\n*p: %s\n",var.p);printf("Size of var is: %zd\n",sizeof(var));return 0;
}

程序的输出:
在这里插入图片描述

可见,结构体变量的大小时32字节,分析:

  1. 大小按理应该是:4+4+10+8=26字节;
  2. 至少不是:4+4+10+18=36字节(那个字符串大小时18字节);
  3. 这说明大小还与对齐方式有关(7.1节中讲到)。

验证:

这里打印4个成员的地址:

printf("成员变量的地址:\na:   %p\nb:   %p\narr:  %p\narr+10:   %p\np:   %p\n",&var.a,&var.b,var.arr,var.arr+10,&var.p);

输出:
在这里插入图片描述

int a地址加上4个字节是int b的地址,int b加4个字节是char arr[10]的地址;
char arr[10]再加10个字节,应该是:0x7fff27ce8b12

这就印证了7.1节中说的对齐问题,p这个指针变量大小时8字节,那么他会放在8字节对齐的地址上,即 0x7fff27ce8b18

7.22 指针型成员变量的正确使用方式

其实就是使用指针的注意问题。

当结构体成员是指针类型时, 不是必须要进行初始化。然而,根据具体的使用场景和需求,初始化指针成员可能是一个良好的编程实践。

如果指针成员在结构体中没有被初始化,它的初始值将是未定义的,也就是说它可能指向任意的内存地址。这可能导致在访问或解引用指针成员时出现未定义行为、段错误或崩溃。

因此,为了避免这些问题,建议在创建结构体实例时初始化指针成员,为其分配合适的内存空间,或者将其指向有效的内存位置。这可以通过以下方式之一实现:

  1. 直接赋值一个有效的指针:

    struct MyStruct {int* ptr;
    };// 初始化指针成员
    struct MyStruct myStruct;
    int value = 42;
    myStruct.ptr = &value;
    
  2. 使用动态内存分配函数(如malloc)为指针成员分配内存(记得要free):

    struct MyStruct {char* str;
    };// 初始化指针成员
    struct MyStruct myStruct;
    myStruct.str = malloc(sizeof(char) * 10);
    if (myStruct.str != NULL) {// 分配成功,可以使用指针成员strcpy(myStruct.str, "Hello");
    }
    
  3. 将指针成员设置为NULL,表示它当前不指向任何有效的内存地址:

    struct MyStruct {float* data;
    };// 初始化指针成员
    struct MyStruct myStruct;
    myStruct.data = NULL;
    

在使用指针成员之前,确保已经进行了适当的初始化或赋值操作,以避免潜在的问题。对于动态分配的内存,还要记得在不需要时及时释放内存,以避免内存泄漏。

7.3 结构体的复合字面量——临时结构体

我前面的代码已经出现过:

Name Jay;
//Jay = {"Jay","Chou",18};  //这是错误写法
Jay = (Name){"Jay","Chou",18};   //正确

符复合字面量是一种语法构造,用于创建临时的、匿名的复合类型的对象,前面文章讲过数组的复合字面量:

intsum =int []){1,1,4,6};

这里结构体的复合字面量是一个道理。

7.4 匿名结构体

前面有一段代码:

typedef struct{char early_aalbum [2][20];
}Album;typedef struct{char first[10];char last[10];int age;Album album;
}Name;

它可以简写为:

typedef struct{char first[10];char last[10];int age;struct {char early_aalbum [2][20];};
}Name;

这个嵌套的匿名结构体的成员可以直接作为外层结构以成员使用:Name.early_aalbum[0]

7.5 伸缩型数组成员

伸缩型数组成员(Flexible Array Member)是C语言中的一种特殊结构体成员,允许在结构体的末尾定义一个数组成员,该数组的大小可以根据需要动态调整。伸缩型数组成员在C语言中的使用主要涉及动态内存分配和管理。

详细介绍:

  1. 定义伸缩型数组成员:

    struct MyStruct {int length;int data[];
    };
    

    在上面的示例中,data成员是一个伸缩型数组,它没有指定数组的大小,只定义了数组的类型。伸缩型数组成员必须是结构体的最后一个成员

  2. 动态分配伸缩型数组成员:
    伸缩型数组成员不能直接使用常规的结构体定义方式来分配内存,因为数组的大小是变化的。要使用伸缩型数组成员,需要结合动态内存分配函数(如malloc)来为结构体分配内存,同时考虑数组的大小。

    struct MyStruct* createMyStruct(int length) {struct MyStruct* myStruct = malloc(sizeof(struct MyStruct) + length * sizeof(int));if (myStruct != NULL) {myStruct->length = length;}return myStruct;
    }
    

    在上面的示例中,使用malloc动态分配了足够的内存空间来容纳结构体本身的大小以及数组成员的大小。

  3. 使用伸缩型数组成员:
    伸缩型数组成员可以像普通数组一样使用。可以通过索引来访问数组元素,但要注意确保不超出数组的有效范围。

    void processMyStruct(struct MyStruct* myStruct) {for (int i = 0; i < myStruct->length; i++) {printf("%d ", myStruct->data[i]);}
    }
    

    在上面的示例中,通过遍历数组成员,打印出数组中的元素。

  4. 释放伸缩型数组成员的内存:
    当不再需要使用结构体及其伸缩型数组成员时,必须记得释放分配的内存以避免内存泄漏

    void destroyMyStruct(struct MyStruct* myStruct) {free(myStruct);
    }
    

    在上面的示例中,使用free函数释放了通过malloc动态分配的内存。

伸缩型数组成员的使用需要小心处理,特别是在内存分配、访问越界等方面。确保正确分配足够的内存,并遵守对数组成员的访问限制,以避免导致未定义行为和内存错误。

7.6 应用——结构体与文件、数据库

结构体在文件和数据库方面的应用广泛:

在文件方面的应用:

  1. 文件读写:结构体可以方便地用于读取和写入文件。通过将结构体的数据以二进制形式写入文件,可以保留结构体的完整信息,并可以随后从文件中读取数据并重新构建结构体。

  2. 文件格式:结构体可以用于定义文件的格式。例如,在图像处理中,可以使用结构体定义图像文件的头部信息、像素数据以及其他元数据。这样可以方便地将整个结构体写入文件或从文件中读取,并以结构化的方式处理图像数据。

  3. 序列化:结构体可以用于对象的序列化和反序列化。通过将结构体的数据转换为特定格式(如JSON、XML等)的字符串,并将其写入文件,可以将对象的状态保存到文件中。然后,可以从文件中读取该字符串,并将其转换回结构体,以还原对象的状态。

在数据库方面的应用:

  1. 数据库表映射:结构体可以用于将数据库表映射到编程语言中的对象。每个结构体字段可以对应数据库表中的列,从而实现对象和数据库之间的数据交互。通过将结构体实例化并将其数据插入数据库表中,或从数据库中查询数据并填充结构体字段,可以在应用程序和数据库之间方便地传输和处理数据。

  2. 数据库查询结果:在执行数据库查询操作后,查询结果通常以结构体的形式返回。每个查询结果的行可以映射到一个结构体实例,结构体的字段表示结果集中的列。这样,可以通过访问结构体的字段来获取和操作查询结果的数据。

  3. 数据库事务:结构体可以用于表示数据库事务中的数据操作。通过将相关数据存储在结构体中,并使用数据库事务管理器执行一系列数据库操作,可以确保数据操作的一致性和原子性。

例:

#include <stdio.h>
#include <mysql.h>struct Employee {int id;char name[50];double salary;
};int main() {// 假设已连接到MySQL数据库并执行查询操作,结果存储在MYSQL_RES对象中MYSQL_RES *result;// 定义结构体数组来存储查询结果struct Employee employees[100];int numRows = 0;// 从查询结果中获取数据并填充结构体数组MYSQL_ROW row;while ((row = mysql_fetch_row(result)) != NULL) {struct Employee employee;employee.id = atoi(row[0]);strcpy(employee.name, row[1]);employee.salary = atof(row[2]);employees[numRows++] = employee;}// 打印查询结果for (int i = 0; i < numRows; i++) {printf("ID: %d, Name: %s, Salary: %.2f\n", employees[i].id, employees[i].name, employees[i].salary);}// 释放查询结果和关闭数据库连接等操作...return 0;
}

对于文件和数据库的操作,应注意数据的一致性、完整性和安全性。正确地处理文件和数据库操作可以提高应用程序的性能和可靠性。此外,在使用结构体进行文件和数据库操作时,还应注意处理错误、异常情况和数据格式兼容性等问题。

八、结构体的应用——链式结构

结构体的重要用途就是创建新的数据形式,如:队列、二叉树、堆、哈希表、图等。

后面开单独章节讲解。



~

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云的云安全审计可以用于哪些安全事件与合规审核?

阿里云的云安全审计可以用于哪些安全事件与合规审核&#xff1f; [本文由阿里云代理商[聚搜云www.4526.cn]撰写] 随着互联网的高速发展&#xff0c;各种互联网应用和服务也在不断涌现。但在运营过程中&#xff0c;安全事件和合规审核问题也不断出现。如何及时、准确地识别并解决…

通俗易懂讲PIC单片机:从一窍不通到入门进步

单片机入门不难------谈PIC系列&#xff08;转自矿石收音机论坛---崂山&#xff09;十年前的老帖子&#xff0c;讲得通俗易懂&#xff0c;分享之。 请看图1 这个8条腿的小螃蟹就是我们的第一顿饭&#xff0c;只要把它吃下去&#xff0c;以后的大餐就好办了。第1、8条腿接电源 …

PIC单片机-Mplab的使用与PIC单片机介绍

内容包括Mplab IDE与Mplab X IDE的使用&#xff0c;触摸功能实践&#xff0c;PIC单片机C与汇编混合编程&#xff0c;PIC单片机介绍等。紫色文字是超链接&#xff0c;点击自动跳转至相关博文。持续更新&#xff0c;原创不易&#xff01; 目录&#xff1a; 一、Mplab IDE的使用…

单片机之汇编语言和C语言(以PIC单片机为例)

目录 计算机语言计算机语言类别中断定时/计数器 C语言数据类型C语言动态数组C语言中void什么意思C语言宏定义单片机C语言的扩充数据类型单片机C语言的运算符单片机C语言的基本语句单片机汇编语言基本语句&#xff08;PIC&#xff09;PIC单片机基础概念PIC16F887&#xff08;40引…

【转】PIC单片机C语言简记

1.PICC安装&#xff1a; PICC编译器可以直接挂接在MPLAB-IDE集成开发平台下&#xff0c;实现一体化的编译连接和原代码调试。使用MPLAB-IDE内的调试工具ICE2000 、ICD2 和软件模拟器都可以实现原代码级的程序调试&#xff0c;非常方便。 首先必须在你的计算机中安装 PICC 编…

PIC单片机入门_C语言编程技术

1.为什么也是C语言&#xff1f; 用C 语言来开发单片机系统软件最大的好处是编写代码效率高、软件调试直观、维护升级方便、代码的重复利用率高等&#xff0c;因此C 语言编程在单片机系统设计中越来越广泛的运用。PIC 单片机的软件开发&#xff0c;同样可以用C 语言实现。 Micro…

PIC单片机与PIC单片机C语言编程简介

对于计算机学院与电子学院相关的同学来说&#xff0c;单片机一定不是一个陌生的概念。在大学的学习生涯中&#xff0c;经常用于教学的是MCS-51系列单片机。其实&#xff0c;除了MCS-51单片机外&#xff0c;还有一类单片机——PIC单片机。 PIC单片机&#xff0c;英文名为Periphe…

Python知识回顾(10)

Day 10 本节主要讲解的是Python中文件操作(IO 技术)方面的知识。 文章目录 1.文件的处理1.1.1 文本文件和二进制文件1.1.2 文件操作相关模块概述1.3 创建文件对象 open()1.4 文本文件的写入1.5 常用编码介绍1.5.1 中文乱码问题1.5.2 write()/writelines()写入数据1.5.3 close(…

安卓手机阅读器_得到电纸书阅读器到底如何,值不值得买?使用一个月后,我告诉你答案!...

1 电纸书墨水屏的发展 一直以来,这世界上只有两种电纸书阅读器(电子书阅读器),一种是Kindle,另一种是其他。当然索尼的电子纸也不错,不过它的定位和价格已经不是普通的看电子书了。 自2007年第一代Kindle问世,如今已经将近13年过去了。Kindle有了更高的知名度,也有了更…

HNU-电子测试平台与工具2-串口实验5次

计算机串口使用与测量 【实验属于电子测试平台与工具】 湖南大学信息科学与工程学院 计科 210X wolf (学号 202108010XXX) 0.环境搭建 在实验开始之前,安装好Ubuntu 20.04操作系统。(这个没有难度) 但要提醒的是,这个ubuntu是xubuntu,而且虚拟硬盘只有10GB的大小…

Java开发 - 让你少走弯路的Redis的主从复制

前言 大家举举手&#xff0c;让我看看还有多少人不会配置Redis的主从&#xff0c;主主这些的。故事发生在前段时间&#xff0c;小伙伴看到了博主的MySQL主从&#xff0c;就问博主有没有Redis的主从配置教程&#xff0c;本以为网上到处都是教程的博主打开网页一搜&#xff0c;好…

程序员の诗 - 启蒙

启蒙 一入挨踢&#xff08;IT&#xff09;门&#xff0c;从此断红尘。 网络席卷人生路&#xff0c;代码看似少年梦。 面朝电脑黑眼圈&#xff0c;一坐又是一整天。 错把代码当成梦&#xff0c;写尽半生皆是空。 然&#xff0c; 机器识 0 1&#xff0c;吾辈创世界&#xf…

linux恶搞指令

alias 指令 linux命令提供了一个有用的工具alias,让我们将需要频繁使用但又过于冗长的命令设置一个别名&#xff0c;以后只需要输入一个简单的别名就可以达到同样的作用 alias 查看当前设置的所有别名 alias cdtest‘cd /src/www/app/account’ 等号两边不能有空格 unalias c…

我爱优雅的代码,我爱搞笑的诗词

天王盖地府&#xff0c;小鸡炖蘑菇&#xff0c;拿了此大奖&#xff0c;才是最幸福。 也不知道什么原因&#xff0c;平时总爱写写各种好玩的东西&#xff0c;作为程序员&#xff0c;也许是一个放松的方式吧&#xff0c;我不喜欢做一个只会写代码的码农&#xff0c;我喜欢能在各个…

用计算机术语写诗,网上盛行写诗软件 电脑作诗毫无逻辑令人喷饭

自从“诗坛芙蓉”赵丽华(BLOG)红遍网络之后&#xff0c;诗歌——一个几乎被忽略的文学体裁又重新引起了大家的关注。 昨日(27日)&#xff0c;记者在浏览网站时发现&#xff0c;目前网络上一款写诗软件十分盛行&#xff0c; 只要输入几个关键字&#xff0c;电脑就自动写出一首诗…

机器学习知识经验分享之五:R语言安装

python语言用于深度学习较为广泛&#xff0c;R语言用于机器学习领域中的数据预测和数据处理算法较多&#xff0c;后续将更多分享机器学习数据预测相关知识的分享&#xff0c;有需要的朋友可持续关注&#xff0c;有疑问可以关注后私信留言。 目录 一、R语言介绍 二、R语言安装…

上海斯歌K2 x 赛博威 | 战略合作深度交流暨签约仪式

2月16日&#xff0c;上海斯歌K2与赛博威进行了战略合作深度交流&#xff0c;并在赛博威广州科学城办公室举办战略合作签约仪式。 为满足客户在数智化建设过程中的多元化需求&#xff0c;上海斯歌K2与赛博威曾多次产生交集。凭借双方多年合作的良好基础&#xff0c;自2022年始&a…

Eclipse教程 Ⅸ

今天继续来学习Eclipse 快速修复、Eclipse 浏览菜单、Eclipse 查找以及Eclipse 悬浮提示的内容&#xff01;老规矩&#xff0c;废话不多说&#xff0c;开始吧。 Eclipse 快速修复 使用快速修复 在 Eclipse 编辑器中当你输入字母时&#xff0c;编辑器会对你输入的内容进行错误…

matplotlib常用功能汇总

文章目录 1.IDE里的1.1 显示模式&#xff08;plt.ion()和plt.ioff()&#xff09;1.2 backend说明 2 jupyter里的3 通用的3.1 cmap3.2 subplot()相关3.3 绘制动态图&#xff08;Animation类&#xff09;3.4 matplotlib利用rcParams配置样式参数 4. 与opencv连用可能遭遇的问题1.…

再谈Linux epoll惊群问题的原因和解决方案

差别是什么&#xff1f;差别只是西装&#xff01; 缘起 近期排查了一个问题&#xff0c;epoll惊群的问题&#xff0c;起初我并不认为这是惊群导致&#xff0c;因为从现象上看&#xff0c;只是体现了CPU不均衡。一共fork了20个Server进程&#xff0c;在请求负载中等的时候&…