从 C 函数返回字符串(或 char *)

问题描述 投票:0回答:3

我需要一个函数来返回各种大小的字符串。 这是我的代码:

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

char *get_option_argument(char *arg, char *shortopt, char *longopt) {
    int len = strlen(arg) ;
    size_t len_shortopt = strlen(shortopt) ;
    size_t len_longopt = strlen(longopt) ;

    // we add an extra space to provide the case when shortopt is included in longopt
    char shortopt2[len_shortopt + 1] ;
    char longopt2[len_longopt + 1] ;

    strcpy(shortopt2, shortopt) ;
    shortopt2[len_shortopt] = ' ' ;
    strcpy(longopt2, longopt) ;
    longopt2[len_longopt] = ' ' ;

    // previous version who doesn't work
    /* strcat(shortopt2, shortopt) ;
    strcat(shortopt2, " ") ;
    strcat(longopt2, longopt) ;
    strcat(longopt2, " ") ; */

    // printf("%s, %s\n", shortopt2, longopt2) ;

    int shortopt_boucle = 0 ;
    int longopt_boucle = 0 ;
    int find_shortopt = 0 ;
    int find_longopt = 0 ;
    int j = 0 ;
    int k = 0 ;

    // We browse arg until we reach the end or find an option.
    for (int i=0; i<len && !(find_shortopt || find_longopt); i++) {
        // if we are not already browsing and we have found a potential start for one
        if (!shortopt_boucle && arg[i] == shortopt2[0]) {
            shortopt_boucle = 1 ;
            j = 0 ;
        }
        // same for longopt
        if (!longopt_boucle && arg[i] == longopt2[0]) {
            longopt_boucle = 1 ;
            k = 0 ;
        }
        // if we are procuring a potential option, we check the current character
        if (shortopt_boucle && j <= len_shortopt)
            if (arg[i] == shortopt2[j])
                j++ ;
            else
                j=0 ;
        // idem
        if (longopt_boucle && k <= len_longopt)
            if (arg[i] == longopt2[k])
                k++ ;
            else
                k=0 ;
        // if we have found one, then stop the loop and use i or j variable to mark the start of the option
        if (j == len_shortopt + 1)
            find_shortopt = 1, j = i+1 ;
        if (k == len_longopt + 1)
            find_longopt = 1, k = i+1 ;
    }

    char *result = malloc(sizeof(char)*len) ; // on utilise une allocation dynamique pour pouvoir le retourner

    // get the word just after the option marker
    if (find_shortopt)
        for (int i=0; arg[j+i] != ' ' && arg[j+i] != '\0' && j+i < len ; i++)
            result[i] = arg[j+i] ;
    else if (find_longopt)
        for (int i=0; arg[k+i] != ' ' && arg[k+i] != '\0' && k+i < len ; i++)
            result[i] = arg[k+i] ;

    return result ;
}

void affiche_vache(char *arg) {
    char *eyes = get_option_argument(arg, "-e", "--eyes") ;
    char *hat = get_option_argument(arg, "-h", "--hat") ;
    if (strlen(eyes)!=2)
        eyes = "oo" ;
    if (strlen(hat)!=6)
        hat = " ^__^ " ;
    char *corp1 = "____" ; // this part is for a next implementation
    char *corp2 = "    " ;
    char *corp3 = "----" ;
    printf("         \\ %s\n", hat) ;
    printf("          \\ (%s)\\_%s__\n", eyes, corp1) ;
    printf("            (__)\\ %s  )\\/\\\n", corp2) ;
    printf("                ||%sw |\n", corp3) ;
    printf("                ||     ||\n") ;
    free(eyes) ;
    free(hat) ;
}

int main() {
    affiche_vache("-e 00 -h _|@#|_") ;
    return 0 ;
}

函数

get_option_argument
必须从给定字符串中提取选项。 例如,
get_option_argument("-e $$", "-e", "--eyes")
必须返回
"$$"
,并且在我第一次调用它时返回,但随后就出错了。

我认为问题出在记忆上。 我首先使用这种方式声明我的字符串:

char result[size]
,但它会导致分段错误和以下警告:
function returns address of local variable
。 这就是为什么我使用
malloc
,但似乎它并没有真正起作用。
malloc 
每次都会在不同的地方分配内存吗? 并且带有
free
的行被注释掉,因为它引发了分段错误。

我为我的嘈杂示例道歉,我尝试用更简单的代码重现相同的情况,但我不太明白它何时工作或不工作。

arrays c segmentation-fault dynamic-memory-allocation
3个回答
0
投票

您可以使用以下代码为您的选项分配空间:

char shortopt2[len_shortopt + 1] ;
char longopt2[len_longopt + 1] ;

strcat(shortopt2, shortopt) ;
strcat(shortopt2, " ") ;
strcat(longopt2, longopt) ;
strcat(longopt2, " ") ;

但是对

strcat
的第二次调用会覆盖数组中的空终止符,这将允许进一步的代码进入日落状态。您需要将上面四行替换为:

strcpy(shortopt2, shortopt);
strcpy(longopt2, longopt);

我无法确切地弄清楚以下代码中的这些循环在做什么,但我怀疑您可以再次超过任一字符串的末尾,因为您使用的数组长度是

for
循环中的终端值,而不是
length - 1
。您可能需要通过调试器运行它,以准确查看失败的位置以及导致哪些变量。

另请注意 Yano 对您的

free
'ed 数组的早期
malloc
的评论。


0
投票

您的代码从第一行调用未定义的行为。

shortopt2
longopt2
未初始化,
strcat
需要有效的 C 字符串作为目标。而且它们太短,无法容纳空间
" "

    char shortopt2[len_shortopt + 2] ;
    char longopt2[len_longopt + 2] ;

    strcpy(shortopt2, shortopt) ;
    strcat(shortopt2, " ") ;
    strcpy(longopt2, longopt) ;
    strcat(longopt2, " ") ;

此外,

strlen
返回
size_t
而不是
int

我没有分析其余的代码


0
投票

我明白了! 事实上,这个bug来自于strcat, 感谢@OldBoy,我在我的代码中添加了以下内容:

printf ("%s, %s\n", shortopt2, longopt2);
,就在要检查的相关行之后,它显示了以下内容: 打电话后

char *eyes = get_option_argument(arg, "-e", "--eyes") ;
char *hat = get_option_argument(arg, "-h", "--hat") ;

代码连续打印,

-e , --eyes 
-e -h , --eyes --hat

这意味着由于一个模糊的原因(这当然有一个很好的理由,但对我来说这是不可理解的),变量

shortopt2
longopt2
保持它的内容。这就是为什么该函数在第二次调用期间没有找到任何内容。 所以我修改了

strcat(shortopt2, shortopt) ;
strcat(shortopt2, " ") ;
strcat(longopt2, longopt) ;
strcat(longopt2, " ") ;

strcpy(shortopt2, shortopt) ;
shortopt2[len_shortopt] = ' ' ;
strcpy(longopt2, longopt) ;
longopt2[len_longopt] = ' ' ;

现在一切正常!

但是如果有人知道为什么这些变量保留其内容......

© www.soinside.com 2019 - 2024. All rights reserved.