在C中的2D char数组中存储和返回本地指针

时间:2017-01-25 07:21:37

标签: c arrays pointers

#include <stdio.h>
#include <stdlib.h> // malloc
#include <string.h> // strlen

char** _malloc_2D_array (char** arg_2D_array,
                         int rows,
                         int cols,
                         int type)
{
    int i = 0;
    int j = 0;

    if (type == 0)
    {
        arg_2D_array = malloc(sizeof(char**) * rows);
        for (; i < rows; i++)
        {
            arg_2D_array[i] = malloc(sizeof(char*) * cols);
        }
    }
    return arg_2D_array;
}

char** _strtok (char* arg_string, const char* arg_delimeter)
{
    char** after_tokenization      = _malloc_2D_array (after_tokenization, 10, 20, 0);
    char*  hold_chars_of_one_group = malloc(sizeof(char*) * strlen(arg_string));

    int j = 0;
    int i = 0;
    int k = 0;

    while (arg_string[i])
    {
        if (arg_string[i] != *arg_delimeter)
        {
            hold_chars_of_one_group[k] = arg_string[i];
            k++;
        }
        else
        {
            after_tokenization[j] = hold_chars_of_one_group;
            j++;
            k = 0;
        }
        i++;
    }

    return after_tokenization;
}

int main()
{
    char** p = _strtok ("anisha,kaul,shizuka,sharma", ",");
    printf ("-%s- p is being printed:", *p);
    return 0;
}

输出:
-sharmaa- p is being printed

我期待所有的话而不是最后一个。此外,还有一个额外的a附加了打印的单词。为什么呢?

这一行:

after_tokenization[j] = hold_chars_of_one_group;

即使我正在递增索引,

似乎也会覆盖2D数组中的地址。为什么?

2 个答案:

答案 0 :(得分:2)

    char** after_tokenization      = _malloc_2D_array (after_tokenization, 10, 20, 0);

调用_malloc_2D_array时,after_tokenization仍然未初始化。 _malloc_2D_array无法使用其值。这个论点完全是多余的。你是否将指针传递给malloc?不,malloc返回指向你的指针。 _malloc_2D_array也不例外。实际上,_malloc_2D_array未使用arg_2D_array的值,但会立即为其分配新值。 IOW,它只不过是一个局部变量。固定:

    char** after_tokenization      = _malloc_2D_array (10, 20, 0);

修复_malloc_2D_array(BTW为什么要在函数名称中添加下划线?它没有任何意义......)

char** _malloc_2D_array (int rows,
                         int cols,
                         int type)
{
    int i = 0;
    int j = 0;
    char** result;

    if (type == 0)
    {
        result = malloc(sizeof(char**) * rows); // BAD

糟糕!这里的星计数错误。我们回过头来回顾一些例子。

     /* Example */ char* str = malloc (length+1);
     /* Example */ int* array = malloc (sizeof(int) * array_length);

在上面的示例中,结果类型有一个星号,sizeof的参数没有星号。您为类型X 分配内存并返回指向X 的指针。指向X的指针的类型比X本身多一个星。固定:

        result = malloc(sizeof(char*) * rows); // GOOD

        for (; i < rows; i++)
        {
            arg_2D_array[i] = malloc(sizeof(char*) * cols); // BAD

同样的错误。当你对它进行空终结时,请留空。定影:                 arg_2D_array [i] = malloc(sizeof(char)*(cols + 1)); // BETTER,sizeof(char)== 1根据定义,您可以跳过它:                 arg_2D_array [i] = malloc(cols + 1); //好的             }         }         返回结果;     }

好的,回到_strtok(顺便说一句,这是一个非常糟糕的功能名称)。

    char*  hold_chars_of_one_group = malloc(sizeof(char*) * strlen(arg_string)); // BAD

与上面相同的错误再加上一个:你还需要一个字符来保存空终止符。固定:

    char*  hold_chars_of_one_group = malloc(sizeof(char) * strlen(arg_string) + 1); 

    int j = 0;
    int i = 0;
    int k = 0;

    while (arg_string[i])
    {
        if (arg_string[i] != *arg_delimeter) // BAD, that's not how strtok works

arg_delimeter中有零个或多个字符,而您只使用第一个字符(不检查它是否存在)。您需要在arg_delimeter修复:

中检查每个字符
        const char* delim;
        int found = 0;
        for (delim = arg_delimiter; *delim && !found; ++delim) // delimiter is spelled this way
          if (*delim == arg_string[i]) found = 1;
        if (!found) // GOOD

继续:

        {
            hold_chars_of_one_group[k] = arg_string[i];
            k++;
        }
        else
        {
            after_tokenization[j] = hold_chars_of_one_group; // PROBLEM 

首先,hold_chars_of_one_group不是以空值终止的。其次,这不是你复制字符串的方式。

            hold_chars_of_one_group[k] = '\0';    
            strcpy(after_tokenization[j], hold_chars_of_one_group)
            j++;
            k = 0;
        }
        i++;
    }

需要处理最后一个令牌,而不是由分隔符分隔。

    hold_chars_of_one_group[k] = '\0';
    strcpy(after_tokenization[j], hold_chars_of_one_group);

并以某种方式表明我们有多少令牌。通常这是通过NULL终止指针数组来实现的。

    j++;
    after_tokenization[j] = NULL;

    return after_tokenization;
}

唉!现在测试:

int main()
{
    char** p = _strtok ("anisha,kaul shizuka;sharma", ",; "); // use different delimiters
    while (*p)  // print all tokens
        printf ("-%s-\n", *p++);
    return 0;
}

为了完整性,这里是固定程序,不间断:

#include <stdio.h>
#include <stdlib.h> // malloc
#include <string.h> // strlen

char** _malloc_2D_array (int rows,
                         int cols,
                         int type)
{
    int i = 0;
    int j = 0;
    char** result;

    if (type == 0)
    {
        result = malloc(sizeof(char*) * rows);
        for (; i < rows; i++)
        {
            result[i] = malloc(cols + 1);
        }
    }
    return result;
}

char** _strtok (char* arg_string, const char* arg_delimeter)
{
    char** after_tokenization      = _malloc_2D_array (10, 20, 0);
    char*  hold_chars_of_one_group = malloc(sizeof(char) * strlen(arg_string) + 1);

    int j = 0;
    int i = 0;
    int k = 0;

    while (arg_string[i])
    {
        const char* delim;
        int found = 0;
        for (delim = arg_delimeter; *delim && !found; ++delim)
          if (*delim == arg_string[i]) found = 1;
        if (!found)
        {
            hold_chars_of_one_group[k] = arg_string[i];
            k++;
        }
        else
        {
            hold_chars_of_one_group[k] = '\0';
            strcpy(after_tokenization[j], hold_chars_of_one_group);
            j++;
            k = 0;
        }
        i++;
    }

    hold_chars_of_one_group[k] = '\0';
    strcpy(after_tokenization[j], hold_chars_of_one_group);
    j++;
    after_tokenization[j] = NULL;

    return after_tokenization;
}

int main()
{
    char** p = _strtok ("anisha,kaul shizuka;sharma", ",; ");
    while (*p)
        printf ("-%s-\n", *p++);
    return 0;
}

答案 1 :(得分:1)

使用您的代码,malloc()不仅char **after_tokenization空间,还需after_tokenization[j]after_tokenization[j]。这是因为malloc()没有指向内存中的任何位置,您需要使用after_tokenization[j] = hold_chars_of_one_group; 进行分配。

而不是:

after_tokenization[j]

哪个会覆盖after_tokenization[j] = malloc(strlen(hold_chars_of_one_group)+1); 的地址,您可以使用:

after_tokenization[j]

返回指向hold_chars_of_one_group的有效指针,现在指针可以占用空间,因为它指向内存中有效的某个位置。您的代码仍然无法工作的原因是您需要将strcpy()的内容复制到此指针中以等待占用空间。

可以使用<string.h>

中的strcpy(after_tokenization[j], hold_chars_of_one_group); 来完成此操作
after_tokenization[j]

现在您已将内容复制到after_tokenization[j]

注意:您可能需要添加空字节和char** after_tokenization = _malloc_2D_array(after_tokenization, 10, 20, 0); 的结尾,否则最终会导致未定义的行为。

另一点需要注意的是这一行:

after_tokenization

这会导致问题,因为{{1}}未在此处初始化,并且变量也是函数调用的参数也很尴尬。

此外,我认为我之前回答了一个非常相似的答案,并且我展示了一些可以完成很多这些事情的代码。