0

我有一个 C 字符串,我想缩短它,以便从第一次出现的 '$' 中删除它。这是我的代码:

int char_search(char exp[], int s, char what) {
    int i, occurrence=-1;
    for (i=0; i < s && occurrence == -1; ++i)
        if (exp[i] == what)
            occurrence = i;

    return occurrence;
}

int shorten(char *exp, int maxlength, char *exp_new) {
    int l, i;
    l = char_search(exp, maxlength, '$');
    exp_new = (char *) malloc((l+1)*sizeof(char));
    exp_new[l] = '\0';
    for (i = 0; i<l; i++) 
        exp_new[i] = exp[i];

    return l;
}

问题是它开始覆盖 exp_new 指针地址,并且只将第一个字符复制到实际数组中。此外, exp_new 出于某种原因返回 NULL。(字符串长度可能不正确,但这不应该搞砸整个事情。)

4

4 回答 4

1

当您想通过函数参数返回指针时,您需要使用双重间接:

int shorten(char *exp, int maxlength, char **exp_new)

更好的签名将是

char* shorten(char *exp, int maxlength, int *length)

直接返回结果的地方。

编辑:当函数名称“shorten”描述了要做什么时,明显的结果应该是缩短的字符串。搜索功能产生的字符串长度是一个可以忽略不计的结果。可以更改函数,以便长度参数可以接受 NULL 指针。在这种情况下,如果调用者不感兴趣,您可以省略长度结果。但这取决于环境。

于 2013-11-12T10:11:18.320 回答
0

这里有几个问题:

  1. 从函数返回值

    • 将地址传递给应返回的实例,并在函数中取消引用该地址以存储数据。
    • 通过 . 从函数返回值return
  2. 寻址数组元素时不需要负值,并且简单的int可能不够宽,所以使用size_t. 如果你的情况-1也应该使用 use ssize_t。C/POSIX 标准保证这两种类型都足够宽以寻址所有机器内存以及每个可能的数组元素。

  3. 在 C 中不要强制转换malloc()/calloc()/realloc().

  4. 声明const什么是不变的。这有助于编译器进行优化,并帮助您编写更好的代码。

  5. 始终测试可能失败的功能。这适用于系统调用以及您自己的函数。

    缺少错误检查:

    • malloc()
    • char_search()

考虑到上面的几点,您的代码可能会更改为如下所示:

 ssize_t char_search(const char * exp, const size_t s, const char what) 
 {
   ssize_t occurrence = -1;

   for (size_t i = 0; i < s && occurrence == -1; ++i)
   {
     if (exp[i] == what)
     {
       occurrence = i;
     }
   }

   return occurrence;
}

ssize_t shorten(const char * exp, const size_t maxlength, char ** pexp_new) 
{
  ssize_t l = char_search(exp, maxlength, '$');
  if ((NULL != pexp_new) && (-1 != l)) /* This way if passing in NULL 
                                      as 3rd argument you just get l. */
  {
    *pexp_new = malloc((l + 1) * sizeof **pexp_new);
    if (NULL = *pexp_new)
    {
      l = -1; /* Indicate failure. */
    }
    else
    {
      size_t i = 0;

      (*pexp_new)[l] = '\0';

      for (; i < l; ++i) 
      {
        (*pexp_new)[i] = exp[i];
      }
    }
  }

  return l;
}
于 2013-11-12T10:30:35.907 回答
0

您的代码中有很多错误。

l = char_search(exp, maxlength, '$'); 您需要检查结果,使其不是-1。

(char *) malloc((l+1)*sizeof(char));您需要检查 malloc 的结果。此外,永远不要转换 malloc 的结果。

for (i = 0; i<l; i++)这不会复制空终止,您先空终止然后再复制数据有点奇怪。memcpy(exp_new, exp, l);我会用和之后替换循环execute exp_new[l] = '\0';

问题的真正根源是晦涩的变量名。没有人,包括你自己,可以说出l应该是什么意思。调用它str_length或其他东西,以便读者可以轻松地告诉“啊,是的,这是字符串的长度,所以它不包括空终止”。此外l1在某些代码编辑器上看起来完全相同,这通常使其成为变量名的错误选择。

此外,exp应该const char*适用于这两个功能。

char *exp_new在堆栈上存储一个指针。该指针仅存在于函数的整个执行过程中。如果要将分配的内存返回给调用者,则必须将参数更改为char** exp_new.

然而,一般来说,返回指向 malloc 内存的指针有点糟糕和危险的做法。确保内存在某处被释放。

于 2013-11-12T10:42:16.923 回答
0

此外, exp_new 出于某种原因返回 NULL。(字符串长度可能不正确,但这不应该搞砸整个事情。)

这有点令人担忧。你忽略了 exp_new “返回” NULL 的事实,这是一个主要的警告信号,表明某些事情是不正确的。

我所期望的最后一件事是写入空指针会产生有用的结果。

您是否正确描述了问题?

如果你想将 exp_new 返回给调用者,你不会这样做。您必须将其声明为 char **,并分配本地分配的字符串

char *local_exp_new = malloc(...) ;
*exp_new = local_exp_new ;
于 2013-11-12T11:40:55.087 回答