在C中返回字符串的正确方法

我有以下代码:

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中编写此函数的正确方法是什么?

c是指针,但没有分配内存。 返回值没问题,就是如何在C中完成。

但是你需要分配内存。

“在C中返回字符串的正确方法”并非真正可行。 在C中, 字符串是一个字符数组(最多包括空字符),并且数组本身不能从函数返回。

函数可以返回指针 。 所以通常的方法是“返回一个字符串”:

  1. 返回一个指针。 char *foo1(...)喜欢char *strdup()

  2. 传入指向字符数组的指针并修改其内容。 void foo2(char *,...)int sprintf(char *dest, const char *format, ...)

  3. 将1 char *foo3(char *, ...) 2 char *foo3(char *, ...)char *strcpy(char *dest, char *src)

  4. 传递指针的地址并更新它。 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); } 

由于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返回时,内容未指定,再次导致未指定的行为。

我更喜欢从调用者分配堆,以便明确谁应该释放它。

 #include  #include  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; }