【问题标题】:C - manipulating char * across functionsC - 跨函数操作 char *
【发布时间】:2021-08-26 08:41:39
【问题描述】:

我有以下函数,当从 main 调用时,当给定一个 int 时,它会返回一个格式化的文件名 (000.jpg) 作为字符串。 (我知道我们可以为此使用 sprintf)

在主要作品中初始化char fn[8] = "000.jpg"

当传递到函数 getfilename() 时,
分配 indiv 字符,例如fn[4] = 'p'; 工作,
但如果我分配 fn = "000.gif"; 它将不起作用
我收到 Bus error: 10

我做错了什么?

(其余代码工作正常,只要我不这样做,输出就是正确的:fn = "000.gif"; 但我想学习如何在跨函数传递时操作字符串)

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

char *getfilename(int counter, char *fn);

int main(void) {
    int counter=14;
    char fn[8]= "000.jpg"; // this is fine

    getfilename(counter, fn);
    printf("%s\n", fn);
}

char *getfilename(int counter, char *fn) {
    fn[7] = '\0';
    fn[4] = 'p';        // this is fine
    fn[5] = 'n';
    fn[6] = 'g';
    //fn = "000.gif";     // this will return Bus error: 10

    // ITOA IMPLEMENTATION FOR 3-DIGIT FILENAME
    int numOfDigits = log10(counter) + 1; 
    for (int i=numOfDigits-1; i>=0; i--, counter/=10) { 
        if (numOfDigits==1) {
            fn[i+2] = (counter % 10) + '0'; 
            fn[0] = fn[1] = '0';
        }
        else if (numOfDigits==2) {
            fn[i+1] = (counter % 10) + '0'; 
            fn[0] = '0';
        }
        else {
            fn[i] = (counter % 10) + '0'; 
        }
    } 
    //////////
    return fn;
}

【问题讨论】:

    标签: c pointers undefined-behavior c-strings string-literals


    【解决方案1】:

    fn = "000.gif" 更改为strcpy(fn, "000.gif")

    还有一点建议。将char fn[8]="000.jpg" 更改为char fn[]="000.jpg" 可能是件好事。如果您将来使用更长的字符串怎么办。你会记得增加数组的大小吗?

    另一方面,如果您确定大小永远不会改变,您可以通过以下方式使代码更加健壮:

    struct filename {
        char fn[8];
    };
    
    char *getfilename(int counter, struct filename *arg) {
        char *fn = arg->fn;
        // Keep the rest the same
    }
    
    int main(void) {
        int counter = 14;
        struct filename f = { "000.jpg" };
        getfilename(counter, &f); // Note the &
        printf("%s\n", f.fn);     
    

    这样,如果您尝试将随机字符串传递给函数,您会收到警告。请注意.-&gt; 基本上是在做同样的事情,但后者与指向结构的指针一起使用。另请注意 - 与数组不同 - 您不必通过指针传递结构。您可以选择直接传递,就像变量一样。返回和分配它们也是如此。在这种情况下,我选择指针只是因为我必须选择一个。

    另一个更方便的选项是:

    char *getfilename(int counter, char (*arg)[8]) {
        char *fn = *arg;
    
        // Keep the rest of the function
    

    实际上我现在写了一个关于该方法的问题:How do I force a warning from using an array of wrong size when passed to function?

    这两种方法各有优缺点。

    【讨论】:

    • 非常感谢,以及关于不要硬编码 arr 大小的第二个提示。
    • 感谢您跟进更多信息。会看看你提出的所有建议。
    【解决方案2】:

    在此声明中

    fn = "000.gif"; 
    

    您为局部指针fn(函数参数是函数局部变量)分配了字符串文字"000.gif" 的第一个字符的地址。然后您尝试更改字符串文字,例如

    fn[0] = fn[1] = '0';
    

    任何更改字符串文字的尝试都会导致未定义的行为。

    来自 C 标准(6.4.5 字符串文字)

    7 不确定这些数组是否是不同的,前提是它们的 元素具有适当的值。 如果程序试图 修改这样的数组,行为未定义。

    您需要更改 main 中声明的原始数组 fn 的内容,而不是更改声明为函数 getfilename 的参数的指针 fn。您可以通过以下方式进行操作

    strcpy( fn, "000.gif" );
    

    【讨论】:

    • 让我看看我是否跟随你:如此有效地 getfilename() 中的 fn 只知道它是指向第一个字母 '0' 的地址的指针,而没有意识到它是为了封装 [8]数组?
    • 好吧,我想我现在明白你的意思了。因此,假设 strcpy() 是在 C 中进行字符串操作的唯一方法是否正确,因为它的实现相当低级?
    • @HanafiHaffidz strcpy 在指针 fn 指向的数组中复制字符串文字“000.gif”的字符。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    • 1970-01-01
    • 2020-04-14
    • 1970-01-01
    • 2021-08-16
    • 1970-01-01
    相关资源
    最近更新 更多