1

我正在研究 C 并希望实现一个字符串连接函数。我实现了以下功能:

void mystr_concat(char* dest, char* src)
{
        char* temp = dest;
        while(*temp)
        {
                temp++;
        }

        while(*src)
        {
                *temp++ = *src;
                src++;
        }
        *temp = '\0';
        return;
}

上述程序的输出是将“src”字符串附加到“dest”字符串。

如果用户传递了一个长度很小的“dest”字符串,以至于它不能再附加“src”字符串。

例如用户有这个字符串和调用的函数

char dest[6] = "abcnd";
char src[100] = "zdfhjksdfskdfsdfsdfj";
mystr_concat(dest, src)

在这种情况下如何检查上述引发条件和解决此问题所需的解决方案?

4

2 回答 2

2

C 不对数组引用执行任何边界检查。如果您需要这样做,您需要将目标数组的最大大小传递给函数,然后验证源是否适合(或根据需要决定截断它),或者引入一个额外的数据结构来跟踪字符串的长度,典型的 Pascal 实现在每个字符串前面加上其最大长度。

这两种解决方案都不是自动的,并且要以安全的方式支持此功能,需要使用 Java 或 C# 等语言来防止使用不安全的构造。

于 2013-10-17T06:49:03.773 回答
0

请注意,当作为函数的参数传递时,字符串会衰减为 char 指针。并且在C中没有可移植的方式来在运行时知道其指针给出的内存区域的大小。因此,您mystr_concat无法知道dest( 除非您以某种方式给出该大小,例如通过将该大小作为附加函数参数传递,例如声明

 void mystr_concat(char* dest, size_t destsize, char* src)

然后你可以用例如调用它

 char destbuf[36];
 strncpy (destbuf, sizeof(destbuf) /*i.e. 36*/, "start"); 
 mystr_concat(destbuf, sizeof(destbuf), "some-more");

请注意,标准snprintf(3)函数具有类似的约定。

另一种可能的方法是确定您的函数返回一个堆分配的字符串,并且它是其调用者对该字符串的责任。free然后你可以编码

char *my_string_catenation (const char* s1, const char* s2)
{
   if (!s1||!s2) return NULL;
   size_t s1len = strlen(s1);
   size_t s2len = strlen(s2);
   char* res = malloc(s1len+s2len+1);
   if (!res) 
    { perror("my_string_catenation malloc"); exit(EXIT_FAILURE); };
   memcpy (res, s1, s1len);
   memcpy (res+s1len, s2, s2len);
   res[s1len+s2len] = (char)0;
   return res;
}

然后你可能会编写类似的代码

 char buf[32];
 snprintf(buf, sizeof(buf), "+%d", i);
 char* catstr = my_string_catenation((i>30)?"foo":"boo", buf);
 do_something_with(catstr);
 free(catstr), catstr = NULL;

上面的例子有点愚蠢,因为一个人可以snprintf不用,my_string_catenation但我想不出一个更好的例子。

在 C 库中,对于谁负责释放一些堆分配的数据有约定是很常见的。您应该记录这些约定(至少在声明它们的头文件中的注释中)。

也许您可能对使用Boehm 的保守垃圾收集器感兴趣;然后你会使用GC_MALLOC 而不是malloc等......你不会打扰free......

于 2013-10-17T07:57:30.267 回答