动态字符数组 - 堆栈

时间:2015-06-02 23:03:13

标签: c multidimensional-array stack

一般背景

我需要一个包含动态数量的字符数组的字符数组,这些数组基于特定文件夹中的文件数量。我能够通过初始化来实现这一目标 char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH]然后在我知道另一个函数发现了多少个文件(未提供)之后再使用FullPathNames = malloc( sizeof(*FullPathNames) * NumOfFiles * MAX_FILENAME_AND_PATHNAME_LENGTH ) )。这个过程完美无瑕。

技术限制

我只能使用ANSI C;我特意使用LabWindows CVI 8.1来编译我的代码。我不能使用任何其他编译器。

一般支持代码

char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH];
size_t Size;
NumOfFiles = NumberOfUserFiles(“*.txt”, “C:\\ProgramData” );
FullPathNames = malloc( sizeof(*FullPathNames) * NumOfFiles * MAX_FILENAME_AND_PATHNAME_LENGTH ) );
Size = sizeof(*FullPathNames) * NumOfFiles;
Memset(FullPathNames,0,Size);

快速解释

上面的代码正在做我想要的。我可以使用以下代码轻松填充此数组:

Strcpy(FullPathNames[0],”Test Word”);

我的问题如下。我希望能够将FullPathNames(一个指向可变数量的字符数组的指针数组)传递给方法。我希望此方法能够删除给定索引处的单个字符数组字符数组。该方法存在的结果是FullPathNames不再包含索引处的给定字符数组。我已成功完成将FullPathNames传递给方法,以便为其添加字符串。我不需要帮助创建数组。我有那个部分在工作。 我的问题仅限于我尝试修改传递给Remove_Element方法的char指针时发生的行为。

下面的代码没有完成,它有一些问题,但在编写它的过程中,我发现了关于指针如何在C中工作的知识差距。我对被告知这些问题不感兴趣除了我发现的问题之外,我还可以解决其他问题。我发现虽然我能够在方法中修改数组本身,但我无法替换它,我正在努力找到一种方法。

我使用以下代码调用该方法。

Remove_Element(FullPathNames,1, NumOfFiles);

我对目前的情况的期望是FullPathNames的原始数据保留,除了我删除的索引,通过从index + 1复制数据,FullPathNames中包含的原始指针当然更新。由于我也想缩小数组,我试图将数组设置为等于新数组。以下信息说明了我尝试调试此行为。

调试信息

当我输入方法时,监视变量会显示以下信息。

FullPathNames = XXXXXX
NewArray = Unallocated
Array = XXXXXX

填写新临时数组后,会发生以下情况:

FullPathNames = XXXXXX
NewArray = YYYYY
Array = XXXXXX

当我退出方法时,会发生以下情况:

FullPathNames = XXXXXX
NewArray = YYYYY
Array = YYYYY

问题的肉

我试图通过将其作为指针传递来修改FullPathNames。我最初使用 realloc 尝试了此任务,但这只是导致了一个空闲指针异常。我相信我理解发生的原因。

我已经确认我实际上通过在初始化FullPathNames的原始代码块中打印包含它的字符串来修改FullPathNames中包含的指针。为了填充数组,我将FullPathNames作为参数传递给调用此 Remove_Element 方法的方法。到目前为止,一切都在起作用,我的预期是如何工作的,除了,我似乎无法修改堆栈上的原始变量。 我相信我可以完成我想要的东西?如果我能理解我无法修改堆栈中的原始变量的原因,我可能能够自己弄明白,那是什么误解和/或 如何以有效的方式实现这一目标?一旦我理解,我可以提供更多的问题澄清,不清楚,我不能发布这个问题从代码所在的位置开始,可能需要一段时间才能完成。

问题中的代码

void Remove_Element( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN], int Index, int Array_Length )    
{
  int i;    
  char String[MAX_FILENAME_AND_PATHNAME_LEN];        
  char (*NewArray)[MAX_FILENAME_AND_PATHNAME_LEN];    
  int NewLength = Array_Length - 1;    
  size_t Size;

NewArray = malloc( sizeof( *NewArray) *  NewLength * ( MAX_FILENAME_AND_PATHNAME_LEN ) );

Size = sizeof( *NewArray ) * NewLength; 

memset(NewArray, 0, Size);
  for ( i = Index; i < Array_Length - 1; i++ )    
  {

    memcpy(String,Array[i+1],MAX_FILENAME_AND_PATHNAME_LEN); // Remove last index to avoid duplication

    strcpy( Array[Index], String );     
  } 
  Array = NewArray;     
}

注意: MAX_FILENAME_AND_PATHNAME_LENGTH = 516;

由于一些反馈,我的最终问题似乎并不清楚。我想了解我可以修改传入方法的原始数组内容的原因,但我无法用另一个数组替换该数组。如果我可以填补我的理解,我可以自己找出解决方案。

4 个答案:

答案 0 :(得分:4)

如果我理解正确,您要做的是修改初始化原始数组的代码部分中的FullPathNames指针。

声明FullPatchNames

char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH]

你基本上声明了一个指向MAX_FILENAME_AND_PATHNAME_LENGTH字符元素数组的指针。通过调用void Remove_Element(...),您只需将此指针的副本提供给函数内有效的局部变量Array。由于这个Array = NewArray;,只更改函数内部指针的本地副本,而不是FullPathNames

如果要更改FullPathNames的值,则必须指向指向函数的指针。 Remove_Element的原型必须如下所示:

 void Remove_Element( char (**Array)[MAX_FILENAME_AND_PATHNAME_LEN],
                      int Index, int Array_Length ) 

现在,Array是指向(一个dimansional)char数组的指针。通过取消引用此指针,您可以更改原始指针FullPathNames以指向您在函数内创建的新对象。您必须将对此功能的调用修改为Remove_Element(&FullPathNames,1, NumOfFiles);。要从Array读取,必须使用*运算符取消引用它:

memcpy(String,*Array[i+1],MAX_FILENAME_AND_PATHNAME_LEN);
...
Array = NewArray;

警告:此代码现在会产生内存泄漏,因为您丢失了对orignal对象的引用。您应该使用代码中某处的free()函数删除它!

答案 1 :(得分:2)

在C语言中,似乎首先缺乏对语法的了解。

select table1.something,
       table2.somethingelse,
       table3.somethingelse2
From   Table1,
       Table2,
       Table3
Where  Table1.ColumnID in ('ID1','ID2','ID3')
And    Table1.SomeColumn = Table2.SomeColumn
And    Table2.AnotherColumn = Table3.AnotherColumn

这是一个例子。此处显示的语法将由c程序员读取为:

  • 分号丢失了 - 也许#define voodoo在哪里!
  • char(* FullPathNames)... - 一个函数指针!哦,等待旁边的方括号?!
  • 也许他想说char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH] 或者他想要char *FullPathNames;嗯......

所以这里是第101个:

char FullPathNames[MAX_FILENAME_AND_PATH_NAME_LENGTH];

取决于char foo[50]; // A fixed size array with capacity 50 (49 chars + '\0' max). char *foo = NULL; // a uninitialized pointer to some char. char (*foo)(); // a pointer to a function of signature: char(void). char *foobar[50]; // This is an array of 50 pointers to char. 所在的位置(在代码文件中,在函数中,在结构定义中),用于它的存储会有所不同。

char foo[50];

现在我们了解了基础知识,让我们看看二维动态数组 char foo1[50]; // zerovars section. char foo2[50] = { 0 }; // initvars section char foo3[50] = "Hello World!"; // also initvars section void FooTheFoo( const char *foo ) { if(NULL != foo ) { printf("foo = %s\n", foo); } } int main(int argc, const char *argv[]) { char bar[50] = "Message from the past."; // bar is located on the stack (automatic variable). FooTheFoo(bar); // fixed size array or dynamic array - passed as a (const pointer) in C. return 0; }
指向char指针的指针。或指向字符指针数组的指针或指向字符数组指针的指针数组。

如上所述,没有&#34; meta&#34;关于char **matrix = NULL;char*指向的内容的信息,最终取消引用的项目将是char类型。而且它是指向指针的指针。

如果你想从中制作一个二维数组,你必须相应地进行初始化:

char **

最后,至少,如何将这样的二维数组传递给函数?由于char **构造不包含关于大小的元信息,在一般(内部不是0终止的字符串)的情况下,你会这样做:

const size_t ROW_COUNT = 5;
const size_T COL_COUNT = 10;
char **myMatrix = malloc(sizeof(char *) * ROW_COUNT);
// check if malloc returned NULL of course!
if( NULL != myMatrix )
{
    for(size_t row = 0; row < ROW_COUNT; row++ )
    {
         myMatrix[row] = malloc(sizeof(char) * COL_COUNT);
         if( NULL == myMatrix[row] ) PanicAndCryOutLoudInDespair();
         for(size_t col = 0; col < COL_COUNT; col++ )
         {
              myMatrix[row][col] = 0;
         }
         // of course you could also write instead of inner for - loop:
         // memset(myMatrix[row], 0, sizeof(char) * COL_COUNT);

    }
}

最后,如果您想再次摆脱2D动态数组,则需要正确释放它。

void FooIt( const char **matrix, size_t rowCount, size_t colCount )
{    // Note: standard checks omitted! (NULL != matrix, ...)
     putchar(matrix[0][0]);
}

关于它我唯一要说的是我留给其他温和的贡献者。我想到的一件事就是如何正确地表达那些多维事物的持久性。

void Cleanup2DArray( char **matrix, size_t rowCount )
{
    for(size_t row = 0; row < rowCount; row++ )
    {
         free(matrix[row];
    }
    free(matrix);
}

有了这个,您应该能够找到代码中出错的地方并修复它。

答案 2 :(得分:1)

您传递的指针只是一个值。它拥有一个地址意味着您可以取消引用它来修改指向的内容,但这并不意味着直接更改其值(您的赋值语句)将影响调用者参数。与C中的其他所有内容一样,如果您想通过地址修改某些内容,那么地址就是您需要执行的操作。如果你正在修改的东西是指针,那么指针的地址(通过指向指针的参数)就是通常规定的解决方案。

但是,我可以告诉你这样做的语法和管家是......在你的情况下没有意义。一个简单的指针很容易,但指向数组的指针并不那么简单。如果我是他,他只会使用函数本身的返回结果,否则当前正在使用该函数void。像这样声明你的函数:

char (*Remove_Element( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN], 
    int Index, int Array_Length ))[MAX_FILENAME_AND_PATHNAME_LEN]
{
    ....

    return Array; // or whatever else you want to return so
                  // long as the type is correct.
}

只需让来电者这样做:

Array = RemoveElement(Array, Index, Array_Length);

答案 3 :(得分:-2)

我最终不得不做一个Sascha建议在方法的参数中使用char **Array)[MAX_FILENAME_AND_PATHNAME_LEN]的变体。

我的解决方案的工作变体如下所示。我必须这样做的原因是因为虽然我能够解除引用(**Array)[MAX_FILENAME_AND_PATHNAME_LEN]我只能修改数组中的第一个字符串数组。

数组已初始化并填充了类似于以下内容的内容。 阵列
  - 字符串1
  - 字符串2
  - 字符串3
  - 字符串4

我可以访问字符串1 *Array[0]没有任何问题,但字符串2 不是*Array[1],因为我的想法是克隆和替换删除索引后的数组我无法使用它。

我复制代码以便发布此答案后修复的唯一已知问题是for循环将跳过新数组中的索引(0,1,2,3等)并且错误地不填充它有数据。生成的数组将替换原始数组。此方法仅适用于初始化要替换的数组的初始代码块。

#define MAX_FILENAME_AND_PATHNAME_LEN MAX_FILENAME_LEN + MAX_PATHNAME_LEN


/*

    This method was designed to free the memory allocated to an array.

*/
void FreeFileAndPathArrays( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN] )
{   
    free( Array );
}                 

/*

    This method was designed to remove an index from an array.  The result of this method will shrink the array by one.

*/
void Remove_Element( char (**ArrayPointer)[MAX_FILENAME_AND_PATHNAME_LEN],int Index, int *Array_Length, char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN] )
{
    int i = 0;
    int j = 0;
    char String[MAX_FILENAME_AND_PATHNAME_LEN];    
    char (*NewArray)[MAX_FILENAME_AND_PATHNAME_LEN];
    char (*GC)[MAX_FILENAME_AND_PATHNAME_LEN];
    int Length = *Array_Length;
    int NewLength = Length - 1;
    size_t Size;

    NewArray = malloc( sizeof( *NewArray) *  NewLength * ( MAX_FILENAME_AND_PATHNAME_LEN ) );

    Size = sizeof( *NewArray ) * NewLength;
    memset(NewArray, 0, Size);
    UI_Display("Test Block:");

    for ( j = 0; j < NewLength; j++ )
    {
        if ( j != Index )
        {
            memcpy(String,Array[j],MAX_FILENAME_AND_PATHNAME_LEN);
            strcpy( Array[Index], String ); 
            Fill(NewArray,String,j);
            UI_Display(String);
        }
    }

    GC = Array;
    *ArrayPointer = NewArray;
    free(GC);          
    *Array_Length = *Array_Length - 1;

}

/*

    This method was designed to place a string into an index.

*/
void Fill( char (*Array)[MAX_FILENAME_AND_PATHNAME_LEN], const char * String, int Index)
{  
        strcpy( Array[Index], String ); 
}

/*

    This method was designed to place fill each string array contained within the array of string arrays with 0's.

*/
void PrepareFileAndPathArrays( char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LEN], int ROWS )
{
    size_t Size;

    Size = sizeof( *FullPathNames ) * ROWS;
    memset(FullPathNames, 0, Size);

}
相关问题