【问题标题】:I can't figure out how to use double pointers我不知道如何使用双指针
【发布时间】:2021-04-26 17:46:30
【问题描述】:

我正在尝试使用动态内存分配,但我无法找出指针。 我把第一部分记下来了。

void addtext(char **wordarray)
{
    char word[N];
    char endword[N] = "end";
    int i=0;
    int words=0;
    while (scanf("%19s", word), strcmp(word,endword))
    {
        words++;
        wordarray = realloc(wordarray, words*sizeof(char *));
        wordarray[words-1] = malloc (N*sizeof(char));
        strcpy(wordarray[words-1], word);
    }


    for (i=0; i<words; i++)
        printf("%s\n", wordarray[i]);
    return ;
}

但是当我尝试在不同的函数中调用同一个数组时遇到了麻烦。

void savetext(char **wordarray)
{
    FILE *savedtext;
    int i=0;
    savedtext = fopen("Saved Text.txt","wt");
    while(wordarray[i][0]!= '\0')
    {
        fputs(wordarray[i++],savedtext);
        fputs(" ",savedtext);

    }

    return ;
}

我的主要功能如下所示:

int main (void)
{
    char **wordarray;
    addtext(wordarray);
    savetext(wordarray);
    return 0;
}

代码的第二部分显然是错误的,但我不确定如何准确调用这些函数。我以前的程序没有使用任何内存分配,所以我没有为指针烦恼。我对 c 真的很陌生,所以任何帮助都将不胜感激。

【问题讨论】:

  • double * 是一个“双指针”。 char ** 是“指向 char 的指针”。
  • wordarray 未初始化,因此 realloc(wordarray) 是未定义的行为。

标签: c pointers pass-by-reference dynamic-memory-allocation c-strings


【解决方案1】:

哦,孩子。好吧,你有两个大问题。

首先,您从未分配过第一个wordarray。至少malloc一次:

char **wordarray = malloc(1);

或者更好的是,第一次使用malloc而不是realloc(并将wordarray初始化为0!):

wordarray = wordarray ? realloc(wordarray, words * sizeof(char *)) 
    : malloc(words * sizeof(char *));

其次,您的addtext 函数正在接收该数组的副本,并对其进行处理。不管是什么东西,它都不会保存在你外面的wordarray 中,在main 中。你需要做的是在你的函数中传递一个指向数组的指针,并通过它编辑main对象:

void addtext(char ***wordarray)
{
    // ...
}

最后,你有一些非常大的性能问题,经常分配缓冲区。使用适当的增长向量实现,或者如果您坚持自己编写,至少将大小增加一倍,或者更好地计算单词并分配正确的大小。

你的end 字符串也被任意分配长度N,不管是什么。你不需要那个,你已经知道长度了。事实上,该字符串已经在二进制文件的只读部分中,只需获取指向它的指针:

const char *endword = "end";

【讨论】:

  • 这个语句 wordarray = wordarray ? realloc(wordarray, words * sizeof(char *)) : malloc(words * sizeof(char *));没有意义。
  • 这句话很强烈,也许你的意思是它对你没有意义?在那条线上你有什么特别不明白的地方吗?
  • 我说了我想说的话。:) 所写的声明没有意义。当空指针用作参数时,函数 realloc 的行为与函数 malloc 相同。所以使用条件运算符没有意义。
【解决方案2】:

也许重构你的程序,让创建字符串成为它自己的函数,并且为了对称,将字符串的存储作为它自己的函数返回。

const int STRING_SIZE = 80;
void createString(char ** strPtr, int stringSize);
void freeString(char * strPtr);


int main(int argc, char ** argv)  {
    char * strValue = NULL;

    createString(&strValue, STRING_SIZE);


    // ... do stuff ...

    freeString(strValue);

} 
//
// end of main
//
void createString(char ** strPtr, int stringSize) {
    //
    // uses pass-by-reference to return *strPtr with allocated storage
    //
    *strPtr = (char *) calloc(stringSize, sizeof(char));
}
void freeString(char * strPtr) {
    if(strPtr == NULL) return;
    free(strPtr);
    strPtr = NULL;
}

【讨论】:

    【解决方案3】:

    对于初学者来说,程序具有未定义的行为至少是因为指针 wordarray 未初始化并且具有不确定的值

    char **wordarray;
    

    并且这个不确定的值在函数addtext中的函数realloc的调用中使用

    wordarray = realloc(wordarray, words*sizeof(char *));
    

    此外,指针按值传递给函数addtext。那就是该函数处理指针值的副本。因此更改副本不会影响存储在原始指针中的值。 main 中的原始指针将保持不变。

    您需要通过指向它的指针通过引用传递指针。

    该函数的另一个问题是在函数addtext之外不会知道存储字符串的数量。您至少需要在数组后面附加一个将用作标记值的空指针。

    在函数savetext的while循环中也是这个条件

    while(wordarray[i][0]!= '\0')
    

    没有意义,因为在函数addtext 中,当用户输入字符串"end" 时,您会停止输入字符串。

    while (scanf("%19s", word), strcmp(word,endword))
                                ^^^^^^^^^^^^^^^^^^^^
    

    所以前面输入的字符串不一定是空字符串。

    这是一个演示程序,展示了如何声明和定义函数addtext

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define N   20
    
    size_t addtext( char ***wordarray )
    {
        char word[N];
        const char *sentinel = "end";
        
        size_t n = 0;
        
        int success = 1;
        
        while ( success && scanf( "%19s", word ) == 1 && strcmp( word, sentinel ) != 0 )
        {
            char **tmp = realloc( *wordarray, ( n + 1 ) * sizeof( char * ) );
            
            success = tmp != NULL;
            
            if ( success )
            {
                ++n;
                *wordarray = tmp;
                ( * wordarray )[n-1] = malloc( strlen( word ) + 1 );
                if ( ( *wordarray )[n-1] ) strcpy( ( *wordarray )[n-1], word );
            }           
        }
    
        return n;
    }   
    
    int main(void) 
    {
        char **wordarray = NULL;
        
        size_t n = addtext( &wordarray );
        
        for ( size_t i = 0; i < n; i++ )
        {
            if ( wordarray[i] != NULL ) puts( wordarray[i] );
        }
        
        for ( size_t i = 0; i < n; i++ )
        {
            free( wordarray[i] );
        }
        
        free( wordarray );
        
        return 0;
    }
    

    如果要输入以下字符串序列

    one
    two
    three
    end
    

    那么程序输出将是

    one
    two
    three
    

    相应地,函数savetext的声明应该改变。在这种情况下,通过引用将指针 wordarray 传递给函数是没有意义的,因为指针本身在函数内没有改变。另外你需要传递分配数组中元素的数量,所以函数声明至少看起来像

    void savetext( char **wordarray, size_t n );
    

    【讨论】:

      猜你喜欢
      • 2011-09-01
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多