【问题标题】:C Function to retrieve argv contents to stringC函数将argv内容检索到字符串
【发布时间】:2021-06-17 22:30:53
【问题描述】:

我没有时间以任何方式提交我的解决方案,但我很沮丧。

我正在编写一个函数,该函数将在执行时采用argv,并将其内容连接到一个字符串中,命令由\n 分隔 像这样"./a.out \n a \n b \n c \n ..etc"

这是 m 代码(它不起作用):

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *my_concat_params(int argc, char **argv){
    char argss[argc];
    
    for (int i = 0; i<argc;i++){
        strcpy(argss[i], argv[i]);
    }
        return argss[0];
    }


int main(int argc, char **argv){
    //char *cmdlne = my_concat_params(argc , argv);
    printf("%d, %s\n", argc, argv[argc-1]);
    return 0;
}

通过指向 pinter 并返回我想要的字符串的正确方法是什么?

【问题讨论】:

  • 您的 argss 在函数堆栈上,返回它是未定义的行为
  • 函数返回后不能使用栈变量,需要在堆上分配缓冲区。
  • 另外,strcpy 要求每个 arg 都是 char *。您将 char 传递给第一个参数。而对于串联,strcat 会更合适。
  • 您有两个选择。在main 中声明输出数组char argss[1000];,并将其作为第三个参数传递给函数。 malloc 数组的内存 char *argss = malloc(1000); 并从函数 return argss; 返回指针

标签: arrays c pointers argv argc


【解决方案1】:

argss 在堆栈中,因此您无法返回它。

您想要一个使用realloc 来增加长度的char *

这里有一些代码[为了清楚起见,我使用|作为分隔符而不是\n]:

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

void *
xrealloc(void *buf,size_t len)
{

    buf = realloc(buf,len);

    if (buf == NULL) {
        perror("realloc");
        exit(1);
    }

    return buf;
}

// RETURNS: pointer to concatenated string
char *
my_concat_params(int argc, char **argv)
{
    char *buf = NULL;
    int dstlen = 0;
    char *src;
    int srclen;
    int seplen = 0;

    // process all arguments
    for (;  argc > 0;  --argc, ++argv) {
        // point to current argument
        src = *argv;

        // get its length
        srclen = strlen(src);

        // grow the output buffer:
        // output length + space for separator + arg length + space for EOS
        buf = xrealloc(buf,dstlen + seplen + srclen + 1);

        // add the separator [for _subsequent_ arguments]
        if (seplen)
            buf[dstlen++] = '|';
        seplen = 1;

        // append the current argument
        strcpy(&buf[dstlen],src);

        // increase output length to account for current argument
        dstlen += srclen;
    }

    // add EOS string terminator
    buf[dstlen] = 0;

    return buf;
}

int
main(int argc, char **argv)
{
    char *cmdlne = my_concat_params(argc,argv);

    //printf("%d, %s\n", argc, argv[argc - 1]);
    printf("%s\n",cmdlne);

    free(cmdlne);

    return 0;
}

对于调用:

./fix1 abc def hello world

输出是:

./fix1|abc|def|hello|world

【讨论】:

  • @OznOg 为简洁起见,对于如此简单的事情,我经常忽略我认为假设的检查,除非它是问题的关键部分,但只是为了保持和平......跨度>
  • 是的,我可以理解,但是需要说明一下,以便可以警告“复制/粘贴”编程...(顺便说一句,即使您进行了编辑,泄漏仍然存在,退出保存它全部)
  • 如果 realloc() 返回 NULL 会发生什么?您不仅泄漏,而且由于丢失了原始指针,因此失去了所有恢复的可能性。发布答案时请使用正确的表格。我们中的一些人必须每天处理这些“错误”,这并不有趣。
  • @MichaëlRoy 除了中止之外,几乎没有什么“恢复”要做。如果您在此处耗尽内存 [您可能不会],则中止是要采取的正确 操作。我知道tmp = realloc(ptr,...); 成语,但我不同意。 “适当的形式”是什么意思?而且,由于我添加了xrealloc,因此存在“泄漏”,但谁在乎,因为我们会立即终止?
  • 我会关心的,你不会通过代码审查。我不是唯一一个。通过在内存耗尽时释放内存,您至少可以尝试做一些比让系统打印 SEGFAULT 更多的事情。
【解决方案2】:

您不能从函数返回堆栈分配的空间。这样做会导致意想不到的结果,其中最好的结果可能是立即崩溃。

最好的做法是在堆上动态分配内存来存储结果。

例子:

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

#ifdef MCCP_MIN_GROW_BY
# error "The name MCCP_MIN_GROW_BY already used, pick a different name"
#endif
#define MCCP_MIN_GROW_BY (128) // pick a value that matches best your expected input 
                               // and available resources.

char *my_concat_params(int argc, const char **argv)
{
    int available_bytes = 0;
    int next_length     = 0;
    int allocated_bytes = 0;
    int bytes_to_add    = 0;

    char* result        = NULL;
    char* current_pos   = NULL;
    char* temp          = NULL;

    result = (char*)malloc(MCCP_MIN_GROW_BY);
    if (!result)
       return NULL;

    *result = 0;   // takes care of the case argc == 0

    current_pos = result;
    available_bytes = MCCP_MIN_GROW_BY;

    while (argc--) 
    {
        // append the next argument to the result, allocating space as needed.
        next_length = strlen(*argv);

        if (available_bytes < next_length + 2)  // '\n' + '\0'
        {
            bytes_to_add = ((next_length + 2) < MCCP_MIN_GROW_BY) 
                             ? MCCP_MIN_GROW_BY
                             : next_length + 2;
            
            // when using realloc, do not lose your original pointer
            // so you can at least free resources gracefully in case 
            // of an error.
            temp = (char*)realloc(result, allocated_bytes + bytes_to_add);
            if (temp == NULL)
            {
                free(result);
                return NULL;
            }
            available_bytes += bytes_to_add;
        }

        memcpy(current_pos, *argv, next_length);  // add the string
        current_pos += next_length;

        *current_pos++  = '\n';                    // the line feed
        *current_pos    = 0;                       // and terminate
        available_bytes -= next_length + 1;        // keep track of space left
        ++argv;
    }
    return result;
}
#undef MCCP_MIN_GROW_BY


int main(int argc, const char **argv)
{
    char *cmdlne = my_concat_params(argc, argv);

    printf("%d, %s\n", argc, cmdlne);

    free(cmdlne);

    return 0;
}

【讨论】:

    猜你喜欢
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-13
    • 2021-02-24
    • 1970-01-01
    • 2017-03-21
    • 2015-04-25
    相关资源
    最近更新 更多