从C中的函数返回并打印字符串

时间:2014-12-08 21:02:19

标签: c function

我正在尝试返回并在C中打印一个函数。打印出来的功能很好,但是当我从函数返回后尝试打印它时,我得到了废话。

我已经尝试了很多,我想我已经看过至少6个与此类似的堆栈溢出帖子,这是我能够接受的最接近的事情,不是分段错误或错误。

代码:

char* getBitstring(unsigned short int instr) {
    //this is what the code below is going to convert into. It is set to default
    //as a 16 bit string full of zeros to act as a safety default.
    char binaryNumber[] = "0000000000000000";

    //....
    //doing things to binaryNumber
    //.....

    printf("don't get excited yet %s\n", binaryNumber); //note, this works

    return binaryNumber;
}
int main(int argc, char *argv[]) {
    char *a = getBitstring(0x1234);
    printf("%s", a); //this fails
    return 0;
}

这是输出:

don't get excited yet 0001001000110100
������e��r�S�����$�r�@�t�$�r�����ͅS�������t����

6 个答案:

答案 0 :(得分:3)

这是因为您返回一个指向自动内存中分配的对象的指针 - 一种未定义的行为。

如果要从函数返回字符串,则需要返回动态分配的块或静态分配的块。

另一种选择是将缓冲区传递给函数,并以文件读取函数的方式提供长度作为函数的返回值:

size_t getBitstring(unsigned short int instr, char* buf, size_t buf_size) {
    ... // Fill in the buffer without going over buf_size
    printf("don't get excited yet %s\n", binaryNumber);
    return strlen(buf); 
}

以下是您调用此功能的方法:

char binaryNumber[] = "0000000000000000";
size_t len = getBitstring(instr, binaryNumber, sizeof(binaryNumber));

现在binaryNumber是调用者上下文中的一个自动变量,因此当调用者需要它时,内存就会存在。

答案 1 :(得分:1)

您的binaryNumber字符数组仅存在于getBitstring函数内。该函数返回后,该内存不再分配给binaryNumber。为了保持分配在该功能之外使用的内存,您可以执行以下两项操作之一:

返回动态分配的数组

char* getBitstring(unsigned short int instr) {
    // dynamically allocate array to hold 16 characters (+1 null terminator)
    char* binaryNumber = malloc(17 * sizeof(char));
    memset(binaryNumber, '0', 16); // Set the first 16 array elements to '0'
    binaryNumber[16] = '\0'; // null terminate the string

    //....
    //doing things to binaryNumber
    //.....

    return binaryNumber;
}

int main(int argc, char *argv[]) {
    char *a = getBitstring(0x1234);
    printf("%s", a);
    free(a); // Need to free memory, because you dynamically allocated it
    return 0;
}

或将数组作为参数传递给函数

void* getBitstring(unsigned short int instr, char* binaryNumber, unsigned int arraySize ) {
    //....
    //doing things to binaryNumber (use arraySize)
    //.....
}

int main(int argc, char *argv[]) {
    char binaryNumber[] = "0000000000000000";
    getBitstring(0x1234, binaryNumber, 16); // You must pass the size of the array
    printf("%s", binaryNumber);
    return 0;
}

其他人建议将binaryNumber数组设置为静态以便快速修复。这可行,但我会避免这种解决方案,因为它是不必要的,并有其他副作用。

答案 2 :(得分:1)

这是人们在学习C时遇到的问题的一个很好的例子,如果他们使用Java或其他更现代的语言进行操作,他们可能不会遇到问题不会向用户公开内存布局的细节。

虽然这里的每个人的答案可能在技术上都是正确的,但我会尝试不同的方法,看看我是否可以回答你的问题而不只是给你一行代码来修复它。

  1. 首先,您需要了解返回时的情况 函数内部定义的变量,如下所示:

    void f(void) {
        int x = 0;
    
        /* do some crazy stuff with x */
    
        return x;
    }
    

    致电return x;时会发生什么?我可能省略了一些 这里有详细介绍,但实质上是调用 context将值存储在中名为x的变量中 那时。 分配用于存储该值的存储空间是 在函数之后不再保证包含该值 结束了。

  2. 其次,我们需要了解在引用数组时会发生什么 以它的名字命名。假设我们有一个'字符串':

    char A[] = "12345";
    

    在C中,这实际上相当于声明一个数组 以\0结尾的字符:

    char A[6] = { '1' , '2' , '3' , '4' , '5' , '\0' };
    

    然后这有点像声明六个char s A[0]A[1],...... ,A[5]。变量A实际上是char *类型,即它是a 包含存储A[0]的存储器地址的指针(开头 数组)。

  3. 最后,我们需要了解调用printf时会发生什么 打印一个这样的字符串:

    printf("%s", A);
    

    你在这里说的是"打印从内存开始的所有字节 地址A,直到您点击包含\0"的字节。

  4. 所以,让我们把它们放在一起。运行代码时,变量binaryNumber是一个包含数组第一个字符的内存地址的指针:binaryNumber[0],这个地址是什么?由函数返回。但是,您已在getBitString内声明了数组,因此我们知道在getBitString结束后,不再保证为数组分配的内存存储相同的值。

    当您运行printf("%s", a)时,您要告诉C到"打印从内存地址a开始的所有字节,直到找到包含\0的字节为止 - 但由于该内存地址只能保证在getBitString内包含有效值,所以你得到的是它在getBitString之外调用时所包含的垃圾。

    那么你可以做些什么来解决这个问题呢?那么你有几种选择,这是一个(非详尽的)清单:

    1. 您在binaryString之外声明getBitString,以便当您尝试在main
    2. 中访问它时它仍然有效
    3. 您将binaryString声明为static,正如其他人所建议的那样,除了实际变量名binaryString仅在函数内有效外,实际上与上面的内容相同,但是分配用于存储数组的内存在函数外部仍然有效。
    4. 在函数中返回之前,使用strdup()函数复制字符串。请记住,如果您执行此操作,则必须free()完成strdup()之后返回的指针,否则您获得的是memory leak

答案 3 :(得分:0)

您的char binaryNumber[]是函数getBitstring()的本地。你不能将局部变量返回给其他函数。

binaryNumber完成执行时,getBitstring()的范围已结束。因此,在main()中,char *a未初始化。

解决方法:

  1. 将数组定义为static,这样它就不会超出范围。 [不是一个好方法,但有效]
    1. 使用动态内存分配并返回指针。 [别忘了以后免费,以免内存泄漏。]
    2. IMO,第二种方法更好。

答案 4 :(得分:0)

使用malloc()函数以动态方式创建返回类型。为字符串结尾创建16 + 1个块。这不安全但容易理解。

char * binaryNumber = (char*) malloc(17*sizeof(char));//create dynamic char sequence
strcpy(binaryNumber,"0000000000000000");//assign the default value with String copy

最终结果将是;

char* getBitstring(unsigned short int instr) {
//this is what the code below is going to convert into. It is set to default
//as a 16 bit string full of zeros to act as a safety default.
char * binaryNumber = (char*) malloc(17*sizeof(char));//create dynamic char sequence
strcpy(binaryNumber,"0000000000000000");//assign the default value with String copy function
//....
//doing things to binaryNumber
//.....
printf("don't get excited yet %s\n", binaryNumber); //note, this works
return binaryNumber;
}
 int main(int argc, char *argv[]) {
 char *a = getBitstring(0x1234);
 printf("%s", a); //this fails
 return 0;
}

当然包括<string.h>库。

答案 5 :(得分:-1)

您需要static

static char binaryNumber[] = "0000000000000000";

如果没有static关键字,则函数返回后自动变量的值将丢失。可能你知道这一点。