关于C中的结构,如何将数据从结构复制到字符串数组

Posted

技术标签:

【中文标题】关于C中的结构,如何将数据从结构复制到字符串数组【英文标题】:Regarding structs in C, how to copy the data from a struct to a string array 【发布时间】:2021-05-21 18:32:57 【问题描述】:

如果使用 mDNS 在网络上找到服务器,我有一个程序。它来自开源堆栈。 目前,我需要以下用例的指导。 用例:每当我运行程序查找服务器时,我计划添加一个额外的逻辑,它尝试连接到提到的服务器,如果连接失败,我会打印一条警告消息,说明服务器上的网络连接可能有故障。

所以代码,

它具有如下定义的类型结构

typedef struct 
    size_t length; /* The length of the string */
    UA_Byte *data; /* The content (not null-terminated) */
 UA_String;

typedef struct 
    UA_UInt32 recordId;
    UA_String serverName;
    UA_String discoveryUrl;
    size_t serverCapabilitiesSize;
    UA_String *serverCapabilities;
 UA_ServerOnNetwork;

默认代码具有这样运行的逻辑:

for(size_t i = 0; i < serverOnNetworkSize; i++) 
            UA_ServerOnNetwork *server = &serverOnNetwork[i];
            printf("Server[%lu]: %.*s", (unsigned long) i,
                   (int) server->serverName.length, server->serverName.data);
            printf("\n\tRecordID: %d", server->recordId);
            printf("\n\tDiscovery URL: %.*s", (int) server->discoveryUrl.length,
                   server->discoveryUrl.data);



            printf("\n\tCapabilities: ");
            /*for(size_t j = 0; j < server->serverCapabilitiesSize; j++) 
                printf("%.*s,", (int) server->serverCapabilities[j].length,
                       server->serverCapabilities[j].data);
            */

            //added below
            printf("%.*s", (int) server->serverCapabilities[0].length,
                                   server->serverCapabilities[0].data);
            printf("\n\tStatus: ");
            printf("%.*s", (int) server->serverCapabilities[1].length,
                                               server->serverCapabilities[1].data);


            printf("\n\n");
        

观察到的输出格式为

Server[0]: name1
    RecordID: 0
    Discovery URL: opc.tcp://hostname2:4840
    Capabilities: LDSME-DESKTOPSIDE
    Status: Available

Server[1]: name2
    RecordID: 1
    Discovery URL: opc.tcp://hostname:4842
    Capabilities: Crane
    Status: Starting...

Server[2]: hostname
    RecordID: 2
    Discovery URL: opc.tcp://hostname:4840
    Capabilities: LDSME-NOTEBOOKSIDE
    Status: AVailable

这将是默认情况。但我计划对提到的每个 URL 进行 ping 操作(或尝试发送消息)以检查网络是否一切正常。 所以我打算提取URL信息。

因此我声明了一个字符数组 A,并尝试使用 strcpy 和 memcpy 函数将内容从 server->discoveryURL.data 复制到数组 A。

但它失败了。

for(size_t i = 0; i < serverOnNetworkSize; i++) 
           UA_ServerOnNetwork *server = &serverOnNetwork[i];
           strcpy(A[i], server->discoveryUrl.data);
           printf("URL %d: %s\n",(unsigned long) i,A[i]);

        

它失败了,甚至没有通过循环。需要一些指导才能获得以下格式的输出

URL 0 : opc.tcp://hostname2:4840
URL 1 : opc.tcp://hostname:4842
URL 2 : opc.tcp://hostname:4840

我也不明白为什么,在结构字符串的 printf 语句中,“%s”最后给出了一个附加字符,而“%.*s”给出了正确的输出。请期待指导。

编辑:我稍微修改了代码并引入了一个新的全局字符数组,并使用了 memcpy 函数。但是我在 URL 字段中获得了一个额外的字符。

char *A[] = ;
int main()

for(size_t i = 0; i < serverOnNetworkSize; i++) 
           UA_ServerOnNetwork *server = &serverOnNetwork[i];        
           A[i] = (char*)UA_malloc(server->discoveryUrl.length+1); 
       memcpy(A[i],server->discoveryUrl.data,server->discoveryUrl.length);  
           printf("URL %d: %.*s\n",(unsigned long) i,A[i]);
        

输出被视为:

URL 0: opc.tcp://o755-gksr:48401
URL 1: opc.tcp://o755-gksr:48421

末尾有一个额外的字符 1,这是错误的。请提供有关如何处理的任何指导。

【问题讨论】:

UA_Byte *data; /* The content (not null-terminated) */ - 评论是一个胖提示 格式字符串“%.*s”有两个参数——一个是长度,另一个是数据。 printf("\n\tDiscovery URL: %.*s", (int) server-&gt;discoveryUrl.length, server-&gt;discoveryUrl.data); 所以如果你想复制server-&gt;discoveryUrl.length 字符,可以使用 memcpy 或 strncpy 来指定长度。但请确保在目的地末尾放置一个字符串终止符。 嗨@JerryJeremiah,我使用了memcpy,但我得到了最后一个字符..你能告诉我如何处理吗? 【参考方案1】:

您需要在复制后使用 '\0' 终止字符串数据。 这样 printf 的 %s 就会知道何时停止:

// first we need some memory for the destination of the copy
A[i] = malloc(server->discoveryUrl.length+1); // +1 for the '\0' at the end
// then we copy exactly the number of characters we want
strncpy(A[i], server->discoveryUrl.data, server->discoveryUrl.length);
// then we add the '\0' terminator
A[i][server->discoveryUrl.length] = '\0'; // add the '\0' at the end

这是一个示例:

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

// defien these so we don't need mDNS
typedef char UA_Byte;
typedef uint32_t UA_UInt32;

typedef struct 
    size_t length; /* The length of the string */
    UA_Byte *data; /* The content (not null-terminated) */
 UA_String;

typedef struct 
    UA_UInt32 recordId;
    UA_String serverName;
    UA_String discoveryUrl;
    size_t serverCapabilitiesSize;
    UA_String *serverCapabilities;
 UA_ServerOnNetwork;

// for testing we only need one of these
UA_ServerOnNetwork serverOnNetwork[1] = 
    
        1,          // recordId
        3,"abcd", // serverName
        3,"efgh", // discoveryUrl
        0,          // serverCapabilitiesSize
        NULL        // serverCapabilities
    
;
int serverOnNetworkSize = sizeof(serverOnNetwork)/sizeof(serverOnNetwork[0]);

int main() 

    // first print it using the %.*s printf formatter
    for(size_t i = 0; i < serverOnNetworkSize; i++) 
        UA_ServerOnNetwork *server = &serverOnNetwork[i];
        printf("Server[%lu]: %.*s", (unsigned long) i,
                (int) server->serverName.length, server->serverName.data);
        printf("\n\tRecordID: %d", server->recordId);
        printf("\n\tDiscovery URL: %.*s", (int) server->discoveryUrl.length,
                server->discoveryUrl.data);
    

    // now make an array of '\0' terminated strings, fill them in, and print them
    printf("\n\nURLs:");
    char *A[serverOnNetworkSize];
    for(size_t i = 0; i < serverOnNetworkSize; i++) 
        UA_ServerOnNetwork *server = &serverOnNetwork[i];
        // first we need some memory for the destination of the copy
        A[i] = malloc(server->discoveryUrl.length+1); // +1 for the '\0' at the end
        // then we copy exactly the number of characters we want
        strncpy(A[i], server->discoveryUrl.data, server->discoveryUrl.length);
        // then we add the '\0' terminator
        A[i][server->discoveryUrl.length] = '\0'; // add the '\0' at the end
        // and finally we print it
        printf("\n\tURL %lu: %s\n", (unsigned long) i, A[i]);
    

    return 0;

在这里试试:https://godbolt.org/z/cbcsdG

【讨论】:

以上是关于关于C中的结构,如何将数据从结构复制到字符串数组的主要内容,如果未能解决你的问题,请参考以下文章

C - 当我尝试将结构从数组复制到结构中包含的数组时出现问题

怎么把一个结构体中的数据复制到另一个相同类型的结构体数组中

无法将固定大小的字节数组从结构复制到 C# 结构中的另一个数组

如果数组大小发生变化以及定义的宏如何在此处计算偏移量,为啥 C 结构中的字符数组的偏移量会有所不同? [复制]

C语言,请问如何将结构体中的结构体拷贝到内存

如何给结构体里的数组复制啊???