【问题标题】:How to choose types for a function prototype?如何为函数原型选择类型?
【发布时间】:2016-04-30 18:22:37
【问题描述】:

如果我有一个像矩阵或树这样的数据结构,并且我想从一个包含上述变量的非常大的函数中提取一个 for 循环,那么调用应该是什么样子?我尝试了以下方法,但出现分段错误。

void write_command(int w, char *argv[], char *string[]) {
    char *dest;

    for (int r = 0; argv[r] != NULL; r++) {
        dest = malloc(sizeof(char *) * strlen(argv[r]) + 1);
        *dest = '0';
        strcpy(dest, argv[r]);
        string[w][r] = *dest;
        free(dest);
    }
}

我想你明白我在做什么,但我应该如何声明变量?我在string[w][r] = *dest; 收到段错误。

我认为您不想看到我正在重构的内容,但它是有史以来最大且最不可读的函数。

static int runCmd(const char *cmd) {
    const char *cp;
    pid_t pid;
    int status;
    struct command structcommand[15];
    char **argv = 0;
    int argc = 1;
    bool pipe = false;
    char *string[z][z];
    char *pString3[40];
    char *pString2[40];
    int n = 0;
    char **ptr1;
    char string1[z];
    bool keep = false;
    char *pString1[z];
    char *pString[z];
    *pString1 = "\0";
    *pString = "\0";
    char *temp = {'\0'};
    int w = 0;
    bool b = false;
    int j = 0;
    int i;
    int p = 0;
    char **ptr;
    char *tmpchar;
    char *cmdtmp;
    bool b1 = false;
    char *dest;
    int y = 0;
    i = 0;
    int h = 0;
    nullterminate(string);
    if (cmd) {
        for (cp = cmd; *cp; cp++) {
            if ((*cp >= 'a') && (*cp <= 'z')) {
                continue;
            }
            if ((*cp >= 'A') && (*cp <= 'Z')) {
                continue;
            }
            if (isDecimal(*cp)) {
                continue;
            }
            if (isBlank(*cp)) {
                continue;
            }
            if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
                (*cp == '+') || (*cp == '=') || (*cp == '_') ||
                (*cp == ':') || (*cp == ',') || (*cp == '\'') ||
                (*cp == '"')) {
                continue;
            }
        }
    }
    if (cmd) {
        cmdtmp = malloc(sizeof(char *) * strlen(cmd) + 1);
        strcpy(cmdtmp, cmd);
        tmpchar = malloc(sizeof(char *) * strlen(cmd) + 1);
        if (tmpchar == NULL) {
            printf("Error allocating memory!\n"); /* print an error message */
            return 1; /* return with failure */
        }
        strcpy(tmpchar, cmd);
        ptr1 = str_split(pString3, cmdtmp, '|');
        if (strstr(cmd, "|") == NULL) {         /* not a pipeline */
            makeArgs(cmd, &argc, (const char ***) &argv, pipe, 0, 0);
            for (j = 0; j < argc; j++) {
                string[0][j] = argv[j];
                structcommand[i].argv = string[0]; /*process;*/
            }
            n++;
        }
        else {
            for (i = 0; *(ptr1 + i); i++) { /* tokenize the input string for each pipeline*/
                n++; /* save number of pipelines */
                int e = 0; /* a counter */
                *pString = "\0"; /* should malloc and free this? */
                strcpy(string1, *(ptr1 + i));
                if ((string1[0] != '\0') && !isspace(string1[0])) { /* this is neither the end nor a new argument */
                    ptr = str_split(pString2, *(&string1), ' '); /* split the string at the arguments */
                    h = 0;
                    for (j = 0; *(ptr + j); j++) { /* step through the arguments */
                        /* the pipeline is in cmdtmp and the argument/program is in ptr[i] */
                        if (ptr + j && !b && strstr(*(ptr + j), "'")) {
                            b = true;
                            strcpy(temp, *(ptr + j));
                            if (y < 1) {
                                y++;
                            }
                        }
                        while (b) {
                            if (*(ptr + j) && strstr(*(ptr + j), "'")) { /* end of quote */
                                b = false;
                                if (y < 1) {
                                    string[i][j] = strcpy(temp, *(ptr + j));
                                }
                                y = 0;
                            }
                            else if (*(ptr + j)) { /* read until end of quote */
                                string[i][j] = temp;
                                continue;
                            } else {
                                b = false;
                                break;
                            }
                        }
                        if (ptr + j) {
                            if (*(ptr + j)[0] == '{') {
                                keep = true;
                            }
                            if (testFn(*(ptr + j))) { /* test for last char */
                                string[i][j - p] = concat(*pString1, *(ptr + j));
                                keep = false;
                                free(*pString1);
                                goto mylabel;
                            }
                            if (keep) {
                                *pString1 = concat(*pString1, *(ptr + j));
                                *pString1 = concat(*pString1, " ");
                                p++;
                            } else {
//                                strcpy(temp, *(ptr + j));
                                b1 = false;
                                int q = j;
                                for (e = 0; *(ptr + q + e); e++) { /* step through the string */
                                    b1 = true;
                                    if (*(ptr + e + q)) {
                                        *pString = concat(*pString, *(ptr + e + q));
                                        *pString = concat(*pString, " ");
                                    }
                                    j = e;
                                }
                                if (makeArgs(*pString, &argc, (const char ***) &argv, pipe, i, h)) {

                                    write_command(&w, argv, string[w]);

                                    /*for (int r = 0; argv[r] != NULL; r++) {
                                        dest = malloc(sizeof(char *) * strlen(argv[r]) + 1);
                                        *dest = '0';
                                        strcpy(dest, argv[r]);
                                        string[w][r] = dest;
                                    }*/
                                    w++;


                                } else {
                                    if (!b1) { /* no args (?) */
                                        for (int r = 0; argv[r] != NULL; r++) {
                                            string[i][r] = argv[r];
                                        }

                                    }
                                }

                            }
                        }
                    }
                    mylabel:
                    free(ptr);
                    dump_argv((const char *) "d", argc, argv);
                }
            }
            free(ptr1);
            free(cmdtmp);
            free(tmpchar);
        }
        for (i = 0; i < n; i++) {
            for (j = 0; DEBUG && string[i][j] != NULL; j++) {
                if (i == 0 && j == 0) printf("\n");
                printf("p[%d][%d] %s\n", i, j, string[i][j]);
            }
            structcommand[i].argv = string[i];
        }
        fflush(NULL);
        pid = fork();
        if (pid < 0) {
            perror("fork failed");
            return -1;
        }
        /* If we are the child process, then go execute the string.*/
        if (pid == 0) {
            /* spawn(cmd);*/
            fork_pipes(n, structcommand);
        }
        /*
         * We are the parent process.
         * Wait for the child to complete.
         */
        status = 0;
        while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR));
        if (pid < 0) {
            fprintf(stderr, "Error from waitpid: %s", strerror(errno));
            return -1;
        }
        if (WIFSIGNALED(status)) {
            fprintf(stderr, "pid %ld: killed by signal %d\n",
                    (long) pid, WTERMSIG(status));

            return -1;
        }
    }
    return WEXITSTATUS(status);


}

【问题讨论】:

  • char *string[] 一个错误输入的char *string[z][z] 实例,还是其他变量?
  • 不,实际上,清楚您要做什么。我最好的猜测是您正在尝试对给定的argv 数组进行深层复制,但在这种情况下,您开始使用的变量声明char *string[z][z]; 是否适合图片并不清楚。也不清楚为什么你似乎在释放函数内部分配的内存。
  • 我试图重构一个大函数,将一个for循环分解为一个函数并调用该函数,但我不习惯传递指针,因为我是OOP。关键的见解是了解我不需要将矩阵作为参数传递,可以将矩阵作为数组传递。现在我尝试通过 struct 进行下一次重构,但我遇到了类似的问题,因为我不是 C 程序员专家。
  • 函数write_commandint w 作为第一个参数,但它使用&amp;w 调用。这不会编译,更不用说段错误。

标签: c function refactoring


【解决方案1】:

我假设您正在尝试制作argv 数组的深层副本,它是一个以NULL 结尾的字符串数组,例如C 程序的main() 函数的第二个参数.您提供的功能似乎假设您已经为目标数组本身分配了空间;它的工作似乎仅限于复制参数字符串。

首先,然后:让我们看看调用者。如果您正在制作标准参数向量的深层副本,那么目标变量的类型应该与 argv 本身的类型兼容(在通俗意义上的“兼容”)。如果副本的生命周期不需要超过宿主函数的返回,那么可变长度数组将是一个不错的选择:

char *copy[argc + 1];

这使您无需手动管理数组本身的内存,但无需管理唯一分配给其元素的任何内存。另一方面,如果您需要副本在声明它的函数返回后仍然存在,那么您将不得不使用手动分配:

char **copy = malloc((argc + 1) * sizeof(*copy));
if (!copy) /* handle allocation failure */ ;

无论哪种方式,您都可以将结果数组或指针本身传递给您的write_command() 函数,并且所需的参数类型相同。将指针传递给copy 是没有意义的,因为该函数不会修改它作为参数接收的指针;相反,它会修改它指向的内存。

这是您似乎想要的函数的签名:

void write_command(char *argv[], char *string[]) {

给定这样的签名,你可以称它为 ...

write_command(argv, copy);

....

你似乎想在里面的循环中执行的关键步骤是

    string[r] = strdup(argv[r]);

您可以使用malloc()、初始化、strcpy() 序列来完成同样的事情,但是当stdrup() 已准备好用于同一任务时,这有点傻。但是,不要忘记检查它的返回值(或者在您的原始代码中,malloc() 的返回值)以防内存分配失败。无论如何,您必须释放write_command() 中分配的内存,因为这会在复制的数组中留下无效的指针。


此外,即使您在调用者中确实有一个 char * 的二维数组,例如 ...

char *copies[n][argc + 1];

...没有任何变化函数write_command()。它不需要知道或关心它复制到的数组是否是二维数组的元素。您只需适当地调用它,例如:

write_command(argv, copies[w]);

无论如何,您必须确保释放复制的参数字符串,但前提是您不再需要它们。同样,您不能在 write_command() 函数中执行此操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-31
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    相关资源
    最近更新 更多