我的函数需要返回一个字符串,并使用索引对其进行构建。理想情况下,我想在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;
}
有没有办法做到这一点?
答案 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,它可以接受临时堆栈变量并对其进行处理。