我有以下代码:
char* get_address_string(PACKAGE* pkg){
char *c;
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1],
pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
代码工作正常。但是,我知道这不是在C中返回字符串的正确方法。我收到警告“c在此函数中使用未初始化”。
在C中编写此函数的正确方法是什么?
答案 0 :(得分:9)
“在C中返回字符串的正确方法”是不可能的。在C中, string 是一个字符数组(最多包括空字符),并且数组本身不能从函数返回。
一个函数可以返回指针。所以通常的方法是“将字符串”返回到:
返回一个指针。 char *foo1(...)
,如char *strdup()
传入指向字符数组的指针并修改其内容。 void foo2(char *,...)
,如int sprintf(char *dest, const char *format, ...)
结合1& 2 char *foo3(char *, ...)
,例如char *strcpy(char *dest, char *src)
传递指针的地址并更新它。 foo4(char **ptr)
,如ssize_t getline(char **lineptr, size_t *n, FILE *stream)
关键是在函数完成后,与指针关联的内存必须有效。返回指向函数的非静态内存的指针是未定义的行为。成功的方法包括在指针中传递调用代码,或者通过内存分配指向一些持久值(如全局变量或字符串常量)的函数来提供它。
在C中编写此函数的正确方法是什么?
目前的设计实践鼓励像#2&上面的#3还提供size_t size
,因此该函数知道可用内存的限制。
char *foo2(char *s, size_t size, const pkg_T *pkg) {
int result = snprintf(s, size, "%02x:%02x:%02x:%02x:%02x:%02x",
pkg->address[0], pkg->address[1], pkg->address[2],
pkg->address[3], pkg->address[4], pkg->address[5]);
// encoding error or not enough room
if (result < 0 || result >= size) return NULL;
return s;
}
另一种方法是分配内存(我赞成上面的内容)。这要求调用代码free()
内存。
#define UINT_MAX_WIDTH (sizeof(unsigned)*CHAR_BIT/3 + 3)
char *foo2alloc(char *s, size_t size, const pkg_T *pkg) {
char buf[(UINT_MAX_WIDTH+3)*6 + 1];
int result = snprintf(buf, sizeof buf, "%02x:%02x:%02x:%02x:%02x:%02x",
pkg->address[0], pkg->address[1], pkg->address[2],
pkg->address[3], pkg->address[4], pkg->address[5]);
// encoding error or not enough room
if (result < 0 || result >= size) return NULL;
return strdup(buf);
}
答案 1 :(得分:4)
c
是一个指针,但没有分配内存。返回值没问题,就是如何在C中完成。
但你需要分配内存。
答案 2 :(得分:0)
由于c
未初始化,sprintf
会写入未知的内存位置,从而导致未指定的行为。它可能会立即崩溃,它可能根本不会崩溃,或者它可能会在某些完全不相关的代码行上崩溃。
您需要通过malloc
为其分配内存来初始化指针。
char* get_address_string(PACKAGE* pkg){
char *c = malloc(20); // enough room for output as 00:11:22:33:44:55 plus null terminator
if (c == null) {
perror("malloc failed");
exit(1);
}
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
请注意,即使您提前知道需要多少内存,也无法通过数组在编译时将其置于一旁。这是错的:
char* get_address_string(PACKAGE* pkg){
char c[20]; // allocated on the stack, contents unspecified on return
sprintf(c, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return c;
}
就是这样:
char* get_address_string(PACKAGE* pkg){
char c[20]; // allocated on the stack, contents unspecified on return
char *p = c;
sprintf(p, "%02x:%02x:%02x:%02x:%02x:%02x", pkg->address[0], pkg->address[1], pkg->address[2], pkg->address[3], pkg->address[4], pkg->address[5]);
return p;
}
由于c
已在堆栈上分配,因此get_address_string
返回时内容未指定,再次导致未指定的行为。
答案 3 :(得分:-3)
我更喜欢从调用者分配堆,以便明确谁应该释放它。
#include <stdio.h>
#include <malloc.h>
bool GetString(char ** retString, size_t size)
{
// use size to do range check
sprintf_s(*retString, size, "blah blah blah");
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
size_t size = 100;
char *data = (char *)malloc(size);
if (data)
{
GetString(&data, size);
free(data);
}
return 0;
}