如何从要在C中的printf中使用的函数返回字符串?

时间:2019-04-01 22:06:58

标签: c c-strings

我的函数需要返回一个字符串,并使用索引对其进行构建。理想情况下,我想在printf()中使用该返回值。我知道给定我的返回类型,我需要返回一个char字符串指针,但是我不能使reg成为字符串指针,因为我需要访问各个元素。另外,我知道我需要malloc(),但是如果将它用作printf的参数,我不知道如何释放该内存。

这是我的代码:

char * printRegister(int num) {
    char reg[] = "$error";
    memset(reg, 0, sizeof(reg));
    switch(num)
    {
        case 0:
            strcpy(reg, "$zero");
            break;
        case 1:
            strcpy(reg, "$at");
            break;
        case 2:
        case 3:
            reg[0] = '$';
            reg[1] = 'v';
            reg[2] = num - 2 + '0';
            reg[3] = '\0';
            break;
        case 4:
        case 5:
        case 6:
        case 7:
            reg[0] = '$';
            reg[1] = 'a';
            reg[2] = num - 4 + '0';
            reg[3] = '\0';
            break;
        case 8:
        case 9:
        case 10:
        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
            reg[0] = '$';
            reg[1] = 't';
            reg[2] = num - 8 + '0';
            reg[3] = '\0';
            break;
        case 16:
        case 17:
        case 18:
        case 19:
        case 20:
        case 21:
        case 22:
        case 23:
            reg[0] = '$';
            reg[1] = 's';
            reg[2] = num - 16 + '0';
            reg[3] = '\0';
            break;
        case 24:
        case 25:
            reg[0] = '$';
            reg[1] = 't';
            reg[2] = num - 16 + '0';
            reg[3] = '\0';
            break;
        case 26:
        case 27:
            reg[0] = '$';
            reg[1] = 'k';
            reg[2] = num - 26 + '0';
            reg[3] = '\0';
            break;
        case 28:
            strcpy(reg, "$gp");
            break;
        case 29:
            strcpy(reg, "$sp");
            break;
        case 30:
            strcpy(reg, "$fp");
            break;
        case 31:
            strcpy(reg, "$ra");
            break;
        default:
            strcpy(reg, "error");
            break;
    }
    return reg;
}

有没有办法做到这一点?

4 个答案:

答案 0 :(得分:2)

  

如何从要在C语言的printf中使用的函数返回字符串?

对于C99或更高版本,请使用复合文字进行临时字符串存储。

首先,重写printRegister()以接受char *缓冲区。

#define  printRegister_N 7
// char * printRegister(int num) {
char * printRegister(char *reg, int num) {
  // char reg[] = "$error";
  // memset(reg, 0, sizeof(reg));
  memset(reg, 0, printRegister_N);  // not really needed anymore with compound literal
  ...
  return reg;
}

形成一个使用复合文字调用printRegister()的宏。

//                                   v---------------------------v  compound literal
#define PRINT_REG(num) printRegister((char [printRegister_N]){ 0 }, (num))

然后致电PRINT_REG(num)。返回的char*(是复合文字的指针)在块的结尾之前一直有效。不需要*alloc()free()

printf("1st:%s  2nd:%s\n", PRINT_REG(0), PRINT_REG(1));

代码仍然使用"%s""%-7s"等类似的"%.*s"装饰。

答案 1 :(得分:2)

当前代码具有未定义的行为,因为您返回了具有自动存储的对象的指针,该对象将在函数返回时超出范围。

有几种方法可以解决此问题:

  • 您可以提供reg static存储类。返回指向reg的指针是可以的,但是随后的对printRegister的调用将覆盖内容,因此您不能多次使用printRegister作为单个printf调用的参数

  • 您可以返回reg的已分配副本,但是调用者将需要释放此内存块,以避免内存泄漏。这使您的工作变得繁琐。

  • 您可以更改printRegister的原型以获取指向目标数组的指针,并在存储寄存器名称的文本表示形式后返回该指针。请注意,在同一printRegister调用中多次调用printf时,您将需要单独的数组。

  • 因为只有33种可能的字符串,所以您可以返回字符串常量。此解决方案简单有效,但是建议将返回类型更改为const char *

这是最后一种方法的实现:

const char *printRegister(int num) {
    static const char * const regname[] = {
        "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
        "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
        "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
        "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
    };
    return (num >= 0 && num < 32) ? regname[num] : "error";
}

答案 2 :(得分:0)

尝试strdup(),它将为您分配内存,并将您想要的任何字符串复制到它。

也可以使用free()释放dynamically allocated的任何内存块。

这里有个例子:

#include <string.h> //note: don't include "string", instead include string.h 
#include <stdlib.h> //note: this header defines free,

int main()
{
    char *data = strdup("the return value of strdup is will be a string containing this");

    /* use dynamically allocated string... */



    free(data); /* free up the memory. */
}

答案 3 :(得分:0)

通过声明一个带有字符串参数的辅助函数

void myprint(char *str) {
    printf("rs: %s\n", str);
}

您可以将printRegister()的实现更改为

void printRegister(int num, void (*fn)(char*)) {
    ...
    fn(reg); // instead of return reg;
}

然后打电话

printRegister(rs, myprint);

通过反转调用方和被调用方的角色来避免动态分配内存的需求; printRegister()的调用者现在提供了一个callback,它可以接受临时堆栈变量并对其进行处理。

Try it online!