为什么C中的malloc(0)在使用char指针时不产生错误

pjngdqdw  于 2023-03-11  发布在  其他
关注(0)|答案(1)|浏览(145)

我正在尝试用c编写一个简单的split函数,在这里你提供一个字符串和一个字符来进行拆分,然后它返回一个拆分字符串的列表:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char ** split(char * tosplit, char delim){
        int amount = 0;
        for (int i=0; i<strlen(tosplit); i++) {
                if (tosplit[i] == delim) {
                        amount++;
                }
        }
        char ** split_ar = malloc(0);
        int counter = 0;
        char *token = strtok(tosplit, &delim);
        while (token){
                split_ar[counter] = malloc(0);
                split_ar[counter] = token;
                token = strtok(NULL, &delim);
                counter++;
        }
        split_ar[counter] = 0;
        return split_ar;
}

int main(int argc, char *argv[]){
  if (argc == 2){
    char *tosplit = argv[1];
                char delim = *argv[2];
                char ** split_ar = split(tosplit, delim);
                while (*split_ar){
            printf("%s\n", *split_ar);
                        split_ar++;
                }
  } else {
    puts("Please enter words and a delimiter.");
  }
}

我使用malloc两次:一次是为指向字符串的指针分配空间,一次是为实际的字符串本身分配空间。奇怪的是:在测试过程中,我发现当我没有分配任何空间时,代码仍然可以工作。
当我删除malloc-line时,我得到了Segfaults或Malloc-assertion错误,所以这些行看起来确实是必要的,尽管它们看起来没有做任何事情。有人能解释一下为什么吗?
我想这和strtok有关;被标记的字符串是在函数作用域之外初始化的,strtok返回指向原始字符串的指针,所以malloc可能根本就不是必需的。我看过许多老的SO线程,但没有找到足够相似的东西来回答我的问题。

uqdfh47h

uqdfh47h1#

为什么C语言中的malloc(0)不会产生错误...?
为什么代码可以在malloc(0)的情况下工作。
调用malloc(0)是可以的。稍后在split_ar[counter] = malloc(0);中使用该指针是 * 未定义的行为 *(UB),因为即使split_ar[0]也试图访问分配的内存之外的内容。
当代码引发 * 未定义行为 * 时,没有应该 * 产生错误 。这是未定义行为 未定义行为 * 中没有 * 已定义行为 *。它可能“工作”,也可能不工作。这是UB。
C并没有给弱编程增加safeguards
如果您需要一种语言来添加对此类错误的额外检查,C并不是最好的答案。
相反,分配正确的数量。在OP的情况下,我认为它最多是amount + 2。(考虑tosplit不包含任何分隔符的情况。)

char **split_ar = malloc(sizeof split_ar[0] * (amount + 2));
if (split_ar == NULL) {
  Handle_OutOfMemory();
}

进一步

代码只尝试复制指针而不复制字符串。

// Worthless code
//split_ar[counter] = malloc(0);
//split_ar[counter] = token;

相反,为字符串分配并复制字符串,研究strdup()

// Sample code using the very common strdup().
split_ar[counter] = strdup(token);

高级

1.使用strspn()strcspn()遍历一个sing并对其进行解析,这样做的好处是可以操作const字符串,并且很容易知道令牌的大小,这在分配时非常有用。
1.使用相同的技术两次来预先计算标记计数和解析。这避免了OP的2个方法中存在的差异。

相关问题