【问题标题】:Converting a char array into an structure similar to int argc and char** argv将 char 数组转换为类似于 int argc 和 char** argv 的结构
【发布时间】:2014-05-17 13:36:43
【问题描述】:

我从文件中读取了一个文本行,我需要将其转换为类似于主函数​​参数的结构。例如,如果 char 数组是 char* text="There are books in the library." 并且我有以下结构定义:

struct mystruct{
   int argc;
   char** argv;
};

如果我有 struct mystruct a,函数 foo(a, text) 我最终得到 a.argc 等于 6,a.argv[0] 等于 那里a.argv[1] 等于 , ... .

C 中是否有任何函数或库可以用于此目的?因为当我们执行 C 主函数时,输入参数的这种转换是自动完成的。

【问题讨论】:

  • shell 进行拆分并将拆分参数传递给exec*() 函数,这些函数将拆分参数传递给被调用的主程序。因此,您最好的选择可能是查看其他人的 shell 的代码。写起来并不难。如果你在结构中记录一个int argmax;,你甚至可以让它相当高效。
  • 如果您将其设为char[] text = ...,那么您可以使用strtok 遍历字符串并保存结果指针。 (也许这是我第一次推荐strtok...)
  • 我认为 *argv[] 会起作用
  • 您也可以使用sscanf读取输入中由空格分隔的字符串,然后使用strdup复制字符串。
  • 命令行参数到argcargv的转换由执行环境完成。没有库函数可以创建它。但是,正如@MattMcNabb 建议的那样,您可以编写一个函数来使用strtokmalloc 在给定text 的情况下构造mystruct。应该不会太难。

标签: c string command-line char arguments


【解决方案1】:

您可以使用strtok 进行拆分,如下所示:

struct split_result {
    int cnt;
    char *buf;
    char **strs;
};

int
split(const char *str, struct split_result *rst)
{
    int idx, str_num;
    char *buf, *sep, **strs;

    buf = strdup(str);
    if (buf == NULL) {
        perror("strdup");
        return -1;
    }

    str_num = 1;
    strs = malloc(str_num * sizeof(char *));
    if (strs == NULL) {
        perror("malloc");
        return -1;
    }

    sep = " \t";
    idx = 0;
    for (strs[idx] = strtok(buf, sep);
         strs[idx];
         strs[idx] = strtok(NULL, sep))
    {
        idx++;
        if (idx >= str_num) {
            str_num += 10;
            strs = realloc(strs, str_num * sizeof(char *));
            if (strs == NULL) {
                perror("realloc");
                return -1;
            }
        }
    }

    rst->cnt = idx;
    rst->strs = strs;
    rst->buf = buf;

    return 0;
}

这是一个测试程序及其输出:

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

struct split_result {
    int cnt;
    char *buf;
    char **strs;
};

int
split(const char *str, struct split_result *rst)
{
    int idx, str_num;
    char *buf, *sep, **strs;

    buf = strdup(str);
    if (buf == NULL) {
        perror("strdup");
        return -1;
    }

    str_num = 1;
    strs = malloc(str_num * sizeof(char *));
    if (strs == NULL) {
        perror("malloc");
        return -1;
    }

    sep = " \t";
    idx = 0;
    for (strs[idx] = strtok(buf, sep);
         strs[idx];
         strs[idx] = strtok(NULL, sep))
    {
        idx++;
        if (idx >= str_num) {
            str_num += 10;
            strs = realloc(strs, str_num * sizeof(char *));
            if (strs == NULL) {
                perror("realloc");
                return -1;
            }
        }
    }

    rst->cnt = idx;
    rst->strs = strs;
    rst->buf = buf;

    return 0;
}

int
main(void)
{
    int i, j;
    struct split_result rst;
    const char *msg[] = {
        "",
        " One",
        " One  Two",
        " One  Two Tree  ",
        "There are books in the library.",
        NULL,
    };

    for (i = 0; msg[i]; i++) {
        if (split(msg[i], &rst) < 0) {
            exit(EXIT_FAILURE);
        }

        printf("msg[%d] = >>%s<<\n", i, msg[i]);
        for (j = 0; j < rst.cnt; j++) {
            printf("cnt = %d: |%s|\n", j, rst.strs[j]);
        }

        free(rst.strs);
        free(rst.buf);
    }

    exit(EXIT_SUCCESS);
}

输出:

$ ./a.out 
msg[0] = >><<
msg[1] = >> One<<
cnt = 0: |One|
msg[2] = >> One  Two<<
cnt = 0: |One|
cnt = 1: |Two|
msg[3] = >> One  Two Tree  <<
cnt = 0: |One|
cnt = 1: |Two|
cnt = 2: |Tree|
msg[4] = >>There are books in the library.<<
cnt = 0: |There|
cnt = 1: |are|
cnt = 2: |books|
cnt = 3: |in|
cnt = 4: |the|
cnt = 5: |library.|

【讨论】:

  • 如果realloc 失败,则返回分配给strsNULL。这将失去对先前分配的内存的处理,从而导致内存泄漏。在调用realloc之前,您应该使用一个临时变量来保存strs
  • @ajay 如果realloc() 失败,则split() 将返回-1 并且程序将终止。但是,可以在此 split() 中的所有 return -1; 之前添加适当的空闲语句,因此当它返回 -1 时,它动态分配的所有内存区域都会被释放。
【解决方案2】:

我认为该文件有一个指定参数数量的数字。如果是这种情况,则创建一个循环并读取每个字符串,直到遇到分隔符(再次假设您被告知有一个分隔符)。如果您没有“the”数量的参数,则在您的结构中添加一个无符号类型的成员,以跟踪读取的单词数。 你真的不需要创建一个 split_function,但是如果你决定创建一个也没有什么坏处 :)

【讨论】:

    猜你喜欢
    • 2020-11-03
    • 1970-01-01
    • 2013-09-08
    • 2011-04-23
    • 2011-07-08
    • 2014-10-09
    • 1970-01-01
    • 2014-01-10
    相关资源
    最近更新 更多