从C中的函数返回char

时间:2010-08-16 21:56:30

标签: c arduino

我已经尝试过Google所能做到的一切,但似乎无法理解这一点。我正在尝试返回一个字符并传递给另一个没有运气的函数。我需要做某种内存位置吗?

char hostname[] = "www.XXXXX.com";
uint8 ipaddr[]  = {XXX,XXX,XXX,XXX};
char uri[]      = "/api/Login/";  
char key[] = API_KEY;  //3490324032-asdfasd-234234
const int port  = 80;

//function to combine uri and key
char combine(char key[], char uri[]) {
  int i = 0;
  int x = 0;
  char long_s[sizeof(uri) + sizeof(key)];

  while(uri[i]) {
      long_s[i] = uri[i];
      ++i;
  }
  while(key[x]) {
      long_s[i] = key[x];
      ++i;
      ++x;
  }
  long_s[i] = '\0';
  //Serial.print(long_s);
  return long_s;  //pointer?
} 

char lon = combine (key, uri);
char* newURI = &lon;

// A get request
GETrequest getSession(ipaddr, port, hostname, newURI);

10 个答案:

答案 0 :(得分:6)

上面的combine函数声称返回一个char,但实际上return long_s返回一个char *作为此行怀疑之后的注释。但是,更改函数以返回char *将不会真正让你在任何地方,因为返回堆栈上的字符串(char数组)的地址是一个危险的游戏 - 一旦函数返回,你不能依赖此指针有效。最好有一个第三个参数组合,char result[]放入结果,或者返回一个malloc的char数组,并确保你在某个时候释放()。

答案 1 :(得分:5)

您的函数返回值为char - 这意味着它返回 char(只能代表一个字符)。字符串由char s数组表示,通常由指针(char *)引用。

所以你需要返回char * - 但这会导致另一个问题。指针必须指向一个比函数调用更长的数组。函数返回后,数组long_s将被销毁,因此不适用。通常的替代方法是允许调用者提供足够大小的缓冲区(还要注意您的循环可以用strcpy()strcat()函数替换):

char *combine(char result[], size_t result_sz, const char key[], const char uri[])
{
  /* Test to see if there is sufficient space */

  if (strlen(uri) + strlen(key) + 1 > result_sz)
  {
    return NULL;
  }

  strcpy(result, uri);
  strcat(result, key);

  return result;
} 

然后你的来电者必须使用:

char lon[1024];
char *newURI = combine (lon, sizeof lon, key, uri);

if (newURI == NULL)
{
    /* Error - URL too long */
}
else
{
    GETrequest getSession(ipaddr, port, hostname, newURI);
}

答案 2 :(得分:2)

您正在尝试返回字符数组,而不是字符。将功能定义为

char *combine(char key[], char uri[])

char *newURI = combine(key, uri);

编辑:正如其他几条评论中所提到的,函数的主体也是一个问题,因为你返回一个只在函数范围内有意义的字符串。你可以改为:

void combine(char key[], char uri[], char *dest)
{
... and place the result in dest
}

char *newURI = (char*)malloc(strlen(key) + strlen(uri) + 1);
combine(key, uri, newURI);
... do whatever
free(combine);

答案 3 :(得分:2)

您没有尝试返回char,而是尝试返回字符串。

C中的char是一个字符(或一个字节)。字符串是一系列字符。是的,您需要某种内存位置,可以使用combinemalloc函数中分配,也可以作为额外参数由调用者提供。或者更可能是两个额外的参数,一个指针和一个长度,以帮助确保有足够的空间来编写连接的字符串。

C中的每个人都按值[*]传递(并返回)。因此,当您返回char时,您只需返回char可能带来的一个可能值。您无法从字符串的开头返回char,获取指向返回值的指针,并获取字符串的其余部分。通过类比,如果我告诉你我正在考虑字母“a”,那么问我是指“问”中的“a”还是“中庸”中的“a”是没有意义的。我只是说一个字母“a”:没有进一步的背景。如果要指示字母“a”所属的字符串,则需要指针。

此外,sizeof不会测量字符串的长度。它为您提供类型或对象的大小,这是它的操作数。由于C语法的不幸特性,您的参数keyuri属于char*类型 - 它们是指针,因此它们的大小是指针的大小,而不是它指向的数组的长度(第一个元素)。因此,您的long_s缓冲区只有8/16字节大(在典型的32/64位架构上),并且会溢出。这会导致未定义的行为,这意味着它可能会崩溃,可能会起作用,或者可能允许攻击者控制您的计算机。

最后,您可以查看标准函数strlenstrcatstrncat,以了解字符串处理在C中的工作原理。以下是一种方法:

char *newURI = malloc(strlen(uri) + strlen(key) + 1);
if (newURL == 0) { /* indicate failure, somehow */ }
strcpy(newURI, uri);
strcat(newURI, key);
GETrequest session = getSession(ipaddr, port, hostname, newURI);
free(newURI); // avoids a memory leak
// do something with the session...

[*]甚至指针也按值传递。

答案 4 :(得分:2)

该函数不返回char,而是返回字符串。 将功能签名更改为

char* combine(char key[], char uri[]) {

(使其返回char *而不是char) 并称之为:

char* newURI = combine(key, uri);

答案 5 :(得分:1)

您说该函数返回char,但您尝试返回char*(对数组的引用)。因此,您需要将函数更改为char*,或者需要返回实际的char。此外,您返回对不再有效的内存的引用,您需要在堆上使用malloc,或者传入指针以填充函数调用。

编辑:进一步澄清

所有这些都是指向uint8或char的数组的指针。

char hostname[] = "www.XXXXX.com";
uint8 ipaddr[]  = {XXX,XXX,XXX,XXX};
char uri[]      = "/api/Login/";  
char key[] = API_KEY;  //3490324032-asdfasd-234234

这是常规数据。

const int port  = 80;

//function to combine uri and key
char combine(char key[], char uri[]) {
  int i = 0;
  int x = 0;

下一行声明一个指向具有8个元素的字符数组的指针。这可能不是你想要的。 sizeof宏正在评估4,因为这是指针的大小(编译并运行下面的程序)。此外,您需要将其更改为char * long_s = malloc(sizeof(uri) + sizeof(key));不要忘记稍后将其释放。

  char long_s[sizeof(uri) + sizeof(key)];
  while(uri[i]) {
      long_s[i] = uri[i];
      ++i;
  }
  while(key[x]) {
      long_s[i] = key[x];
      ++i;
      ++x;
  }
  long_s[i] = '\0';
  //Serial.print(long_s);

这将返回指向您刚刚填充的数组的指针,而不是实际的char。

  return long_s;  //pointer?
} 

这些下一行应该是char * newURI = combine(key, uri);

char lon = combine (key, uri);
char* newURI = &lon;

// A get request
GETrequest getSession(ipaddr, port, hostname, newURI);

编辑:试试这个:

#include <stdio.h>

void test(char k[])
{
    printf("%d\n", sizeof(k));
}

int main ()
{
    char* key[100];
    test(key);
    printf("%d\n", sizeof(key));
    return 0;
}

答案 6 :(得分:1)

你有几个问题:

  1. 你正在返回一个指向局部变量的指针。虽然您可能会意外地从该结果中打印出合理的输出结果,但这里存在一个错误,即您正在访问不再有效的数据。一旦函数返回

  2. ,结果指向的局部变量就不再“活着”
  3. 您正在调整结果缓冲区的大小。 urikey参数确实是指针(请参阅Sizeof array passed as parameter),所以

    char long_s[sizeof(uri) + sizeof(key)];
    

    实际上为你提供了一个足以容纳2个指针的字符数组,这个字符不一定足以容纳你的字符串。

  4. 您需要决定如何管理组合字符串。有几种选择:

    1. 让你的来电者通过一个缓冲区来使用(连同大小,以防止出现超限错误)

    2. 让函数分配缓冲区并要求调用者在不再需要时释放它。

    3. 使用选项2的示例:

      //function to combine uri and key
      char* combine(char const* key, char const* uri) {
          int len = strlen(key) + strlen(uri) + 1; /* don't the '\0' terminator */
      
          char* pResult = malloc(len);
      
          if (pResult) {
              /* we got a buffer */
              strcpy( pResult, uri);
              strcat( pResult, key);
          }
      
          return pResult; /* will return NULL on failure */
                          /* caller is responsible for calling free() */
      } 
      

答案 7 :(得分:0)

您还需要更改combine以处理char*

//function to combine uri and key
void combine(char key[], char uri[], char long_s[]) {
  int i = 0;
  int x = 0;
  while(uri[i]) {
      long_s[i] = uri[i];
      ++i;
  }
  while(key[x]) {
      long_s[i] = key[x];
      ++i;
      ++x;
  }
  long_s[i] = '\0';
  //Serial.print(long_s);
}

char newURI = malloc(strlen(uri) + strlen(key) + 1);
combine(key, uri, newURI);

然后,您还必须将lon参数更改为char*

正如评论所指出的那样,你实际上必须做更多的事情,因为long_s是一个局部变量。

您可能需要更改函数以将lon作为参数并在函数外部初始化它。

同样,这是快速代码,你必须根据自己的需要定制它(并进行垃圾收集)。

答案 8 :(得分:0)

如果您计划返回指向char的指针,则应将您的函数声明为

char *combine (char key[], char uri[])
{
    //...etc...
    return long_s;  //pointer?
} 

答案 9 :(得分:0)

第一个问题:您显然是在尝试从combine函数返回一个字符串,而不是字符。那么你为什么要宣布它为char?它需要返回字符串的类型,即char*

第二个问题:函数无法在C中真正获取数组参数。当您将combine声明为采用两个数组参数时,它与将其声明为采用两个指针参数完全等效。最好将指针显式声明为参数,因为这样你就有机会避免下一个问题。到目前为止,我们有:

char* combine(char *key, char *uri) {

第三个问题:由于keyuri不是数组而是指针,sizeof(key)sizeof(uri)会给出指针的大小,这在这里没用。相反,你需要的是弦的长度。并且您需要添加1以允许组合字符串末尾的“0”。

第四个问题:如果将long_s分配为本地数组变量,则在函数末尾回收分配给它的内存。所以你不能退货。为了获得在函数结束时仍然存在的一块内存,您需要使用malloc使用动态内存分配:

char *long_s = malloc(strlen(key) + strlen(uri) + 1);
if (long_s == NULL) { ... /*out of memory*/ }

修复这些问题后,您可以直接执行char *newURI = combine(key, uri);。完成使用后不要忘记free(newURI)

如果这是一个真正的程序而不是学习练习,请学习使用字符串库函数。特别是,您的combine函数更容易编写为strcpy,后跟strcat