柔性数组(变长数组)介绍

news/2024/7/24 9:25:41 标签: c++

柔性数组简介

柔性数组,或称为可变长度数组,是一种在C语言结构体定义中使用的特殊数组,它允许结构体拥有一个可变大小的数组成员。柔性数组成员必须是结构体的最后一个成员,且它不占用结构体大小的计算,这使得可以动态地分配超出结构体声明大小的内存,从而容纳变长的数据。

优点

  • 动态内存管理:使用柔性数组可以根据需要动态地分配更多的内存,这在处理不确定大小的数据时非常有用。
  • 内存连续性:柔性数组的数据存储在单一连续的内存块中,这有利于提高内存访问效率。
  • 简化指针操作:通过减少额外的指针或分配,柔性数组可以简化代码和降低出错率。

如何使用柔性数组

要在C语言中使用柔性数组,你需要在结构体定义中将最后一个元素声明为未指定大小的数组。这里是一个典型的使用示例:

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

typedef struct {
    int length;
    double data[]; // 柔性数组成员
} FlexibleArray;

int main() {
    int desiredLength = 5;
    // 分配内存时,包括结构体基础大小和数组所需的额外空间
    FlexibleArray *array = (FlexibleArray *)malloc(sizeof(FlexibleArray) + sizeof(double) * desiredLength);
    array->length = desiredLength;
    for (int i = 0; i < array->length; i++) {
        array->data[i] = i * 2.0;
    }
    for (int i = 0; i < array->length; i++) {
        printf("Element %d = %f\n", i, array->data[i]);
    }
    free(array);
    return 0;
}

注意事项

  • 柔性数组成员不占用结构体大小的计算。
  • 只有位于结构体最后一个成员位置的数组可以被声明为柔性数组。
  • 分配含有柔性数组的结构体时,需要手动计算额外内存的需求。
  • 使用完毕后,需要手动释放内存以避免内存泄露。

在网络通信中使用柔性数组

消息结构

// message.h
#ifndef MESSAGE_H
#define MESSAGE_H

#include <stdint.h>

typedef struct {
    uint32_t length; // 消息长度
    char data[0];    // 数据部分
} message_t;

#endif

服务端

// server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "message.h"


int main(int argc, char *argv[]) {
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;

    if (argc < 2) {
        fprintf(stderr, "ERROR, no port provided\n");
        exit(1);
    }

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) printf("ERROR opening socket\n");
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
        printf("ERROR on binding\n");
    
    listen(sockfd, 5);
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) printf("ERROR on accept\n");
    
    uint32_t msg_length;
    n = read(newsockfd, &msg_length, sizeof(msg_length));
    if (n < 0) printf("ERROR reading from socket\n");
    msg_length = ntohl(msg_length); // 确保网络字节序转换为主机字节序

    message_t *msg = (message_t*)malloc(sizeof(message_t) + msg_length - 1); // 分配额外的空间
    n = read(newsockfd, msg->data, msg_length);
    if (n < 0) printf("ERROR reading from socket\n");

    printf("Here is the message: %s\n", msg->data);
    close(newsockfd);
    close(sockfd);
    return 0; 
}

客户端

// client.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include "message.h"
int main(int argc, char *argv[]) {
    int sockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    char buffer[256];
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        printf("ERROR opening socket\n");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(portno);

    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        printf("ERROR connecting\n");

    printf("Please enter the message: ");
    bzero(buffer,256);
    fgets(buffer,255,stdin);
    uint32_t msg_length = strlen(buffer);

    // 发送消息长度
    uint32_t n_msg_length = htonl(msg_length); // 转换为网络字节序
    write(sockfd, &n_msg_length, sizeof(n_msg_length));

    // 发送消息数据
    n = write(sockfd, buffer, msg_length);
    if (n < 0) 
         printf("ERROR writing to socket\n");

    close(sockfd);
    return 0;
}


http://www.niftyadmin.cn/n/5425441.html

相关文章

数据结构之树(Topk问题, 链式二叉树)

一.topk问题 取N个数中最大(小)的前k个值,N远大于k 这道题可以用堆的方法来解决,首先取这N个数的前k个值,用它们建堆 时间复杂度O(k) 之后将剩余的N-k个数据依次与堆顶数据进行比较,如果比堆顶数据大,则将堆顶数据覆盖后向下调整 时间复杂度(N-k)*log(N) 总共的时间复杂度…

C语言malloc动态内存开辟

由于各种原因&#xff0c;然后一个多星期没有学习过C语言了&#xff0c;然后就也没有进行更新&#xff0c;今天开始继续学习C语言&#xff0c;然后下面是使用malloc开辟动态内存的一个例子&#xff1a;我想大家都应该可以看明白。 #define _CRT_SECURE_NO_WARNINGS 1#include…

c#递归函数

在 C#中&#xff0c;递归函数是指在函数内部直接或间接调用自身的函数。递归函数在解决一些问题时非常有用&#xff0c;例如遍历树形结构、递归计算等。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的木材表面缺陷检测系统(深度学习+Python代码+UI界面+训练数据集)

摘要&#xff1a;开发高效的木材表面缺陷检测系统对于提升木材加工行业的质量控制和生产效率至关重要。本篇博客详细介绍了如何运用深度学习技术构建一个木材表面缺陷检测系统&#xff0c;并提供了完整的实现代码。该系统采用了强大的YOLOv8算法&#xff0c;并对YOLOv7、YOLOv6…

【RepVGG网络】

RepVGG网络 RepVGG网络是2021年由清华大学、旷视科技与香港科技大学等机构的研究者提出的一种深度学习模型结构&#xff0c;其核心特点是通过“结构重参数化”&#xff08;re-parameterization&#xff09;技术&#xff0c;在训练阶段采用复杂的多分支结构以优化网络的训练过程…

基于SpringBoot的“逍遥大药房管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“逍遥大药房管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统首页界面图 药品信息界面图 疫情常识界…

【力扣刷题】Leetcode 2592 最大化数组的伟大值

文章目录 1. Leetcode 2592 最大化数组的伟大值 1. Leetcode 2592 最大化数组的伟大值 题目链接 本题思考的关键点&#xff1a;① nums 的最小值要参与匹配&#xff0c;否则更大的数字更难匹配上&#xff1b;② nums 最小值要与次小值进行比较&#xff0c;这样才能贡献值最大…

vue-treeselect的下拉列表中的字体样式修改

vue-treeselect的样式文件为&#xff1a;riophae/vue-treeselect/dist/vue-treeselect.css 从使用的import可以找到 import Treeselect from "riophae/vue-treeselect"; import "riophae/vue-treeselect/dist/vue-treeselect.css"; 打开这个样式文件&a…