不知道如何实现指向char的指针数组的指针

时间:2018-09-26 11:17:38

标签: c arrays pointers

我不太喜欢指针。我知道足以获取指向char的指针数组,如下面的第一个示例所示。但是我不想传递整个指针数组,因为它占用了堆栈上太多的空间。我想做的是将单个指针传递给为指针数组分配的内存。我不知道该怎么做。

该程序有效:

#include "pch.h"
#include "$StdHdr.h"
#include "TmpTstPtr1.h"

#define SRC_LIN_SIZ 150

int main(int ArgCnt, char * ArgVal[])
{
    char        InpFilPth[MAX_PATH + 1];
    FILE        * InpFilPtr;
    char        ** SrcArr;
    unsigned    Sub1;
    unsigned    SrcArrCnt = 0;

    strncpy_s(InpFilPth, "TmpTstPtr1.cpp", strlen("TmpTstPtr1.cpp"));
    fopen_s(&InpFilPtr, InpFilPth, "r");
    SrcArr = (char **)malloc(999999 * sizeof(char *));
    LodSrcArr(InpFilPtr, SrcArr, &SrcArrCnt);
    for (Sub1 = 0; Sub1 < SrcArrCnt; Sub1++) {
        printf("SrcArr[%d] = %s\n", Sub1, SrcArr[Sub1]);
    }
    fclose(InpFilPtr);

    return 0;
}

void LodSrcArr(FILE * InpFilPtr, char ** SrcArr, unsigned * SrcArrCnt)
{
    char        SrcLin[SRC_LIN_SIZ + 1];
    char        * GetStrPtr;


    GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
    while (GetStrPtr != NULL) {
        SrcArr[*SrcArrCnt] = (char *)malloc(SRC_LIN_SIZ + 1);
        //      CpySiz(SrcArr[*SrcArrCnt], strlen(SrcLin) + 1, SrcLin);
        errno = strncpy_s(SrcArr[*SrcArrCnt], SRC_LIN_SIZ + 1, SrcLin, strlen(SrcLin));
        (*SrcArrCnt)++;
        GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
    }
}


char * GetStr(char * Str, const int MaxChr, FILE * InpFilPtr)
{
    char        * InpRtnVal = NULL;
    unsigned    Sub1;

    //  Get string from input file.  Find the end of the string if something entered.
    InpRtnVal = fgets(Str, MaxChr + 1, InpFilPtr);
    if (InpRtnVal != NULL) {
        Sub1 = 0;
        while (Str[Sub1] != '\n' && Str[Sub1] != '\0') {
            Sub1++;
        }
        //  Replace newline with null.
        if (Str[Sub1] == '\n') {
            Str[Sub1] = '\0';
        }
    }
    return InpRtnVal;

以下程序甚至没有关闭:

#include "pch.h"
#include "$StdHdr.h"
#include "TmpTstPtr2.h"

#define SRC_LIN_SIZ 150

int main(int ArgCnt, char * ArgVal[])
{
    char        InpFilPth[MAX_PATH + 1];
    FILE        * InpFilPtr;
    char        ** SrcArr;
    unsigned    Sub1;
    unsigned    SrcArrCnt = 0;
    char        *** SrcArrPtr = NULL;

    strncpy_s(InpFilPth, "TmpTstPtr2.cpp", strlen("TmpTstPtr2.cpp"));
    fopen_s(&InpFilPtr, InpFilPth, "r");
    SrcArr = (char **)malloc(999999 * sizeof(char *));
    SrcArrPtr = &SrcArr;
    LodSrcArr(InpFilPtr, SrcArrPtr, &SrcArrCnt);
    SrcArrPtr = &SrcArr;
    for (Sub1 = 0; Sub1 < SrcArrCnt; Sub1++) {
//      printf("SrcArr[%d] = %s\n", Sub1, SrcArr[Sub1]);    // got "Exception thrown: read access violation. it was 0xCDCDCDCD."
        printf("SrcArr[%d] = %s\n", Sub1, **SrcArrPtr);     // get 75 lines of garbage
        (**SrcArrPtr) += sizeof(char *);
    }
    fclose(InpFilPtr);

    return 0;
}


void LodSrcArr(FILE * InpFilPtr, char *** SrcArrPtr, unsigned * SrcArrCnt)
{
    char        SrcLin[SRC_LIN_SIZ + 1];
    char        * GetStrPtr;


    GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
    //  while (GetStrPtr != NULL and *SrcArrCnt == 0) {
    while (GetStrPtr != NULL) {
        **SrcArrPtr = (char *)malloc(SRC_LIN_SIZ + 1);
        //      CpySiz(SrcArr[*SrcArrCnt], strlen(SrcLin) + 1, SrcLin);
        errno = strncpy_s(**SrcArrPtr, SRC_LIN_SIZ + 1, SrcLin, strlen(SrcLin));
        (**SrcArrPtr) += sizeof(char *);
        (*SrcArrCnt)++;
        GetStrPtr = GetStr(SrcLin, SRC_LIN_SIZ, InpFilPtr);
    }
}


char * GetStr(char * Str, const int MaxChr, FILE * InpFilPtr)
{
    char        * InpRtnVal = NULL;
    unsigned    Sub1;

    //  Get string from input file.  Find the end of the string if something entered.
    InpRtnVal = fgets(Str, MaxChr + 1, InpFilPtr);
    if (InpRtnVal != NULL) {
        Sub1 = 0;
        while (Str[Sub1] != '\n' && Str[Sub1] != '\0') {
            Sub1++;
        }
        //  Replace newline with null.
        if (Str[Sub1] == '\n') {
            Str[Sub1] = '\0';
        }
    }
    return InpRtnVal;
}

正如评论所说,当我尝试通过下标访问SrcArr时,出现运行时错误。当我尝试通过指针访问时,我得到了垃圾。问题可能出在我说SrcArrPtr = &SrcArr;的地方。我不知道这是否有意义,但是后续每行打印的垃圾内容要短4个字符。好像它实际上是在打印指针数组本身,而不是它们所指向的字符串一样。我不知道。

我如上所述进行编码的原因是为了使程序得以编译。我以前从未尝试使用3个指针。我要做什么甚至有可能吗?如果是这样,有人可以告诉我如何?对它如何工作的解释会很好,但不是必须的。 (尽管我认为这并不重要,但我正在使用Visual Studio 2017。)

TIA。

3 个答案:

答案 0 :(得分:2)

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

void foo(char* bar[10]) { // a real array
    for (int i = 0; i < 10; ++i) {
        bar[i] = calloc(2, 1);
        bar[i][0] = '0' + i;
    }
}

void xox(char **qux) { // pointer to some char-pointers on the heap
    for (int i = 0; i < 10; ++i) {
        qux[i] = calloc(2, 1);
        qux[i][0] = '0' + i;
    }
}

int main(void)
{
    char* bar[10]; // a "real" array
    foo(bar);

    for (size_t i = 0; i < 10; ++i)
        puts(bar[i]);
    putchar('\n');

    // cleanup:
    for (size_t i = 0; i < 10; ++i)
        free(bar[i]);

    // plan b:
    char **qux = calloc(10, sizeof(*qux));
    xox(qux);

    for (size_t i = 0; i < 10; ++i)
        puts(qux[i]);
    putchar('\n');

    // cleanup:
    for (size_t i = 0; i < 10; ++i)
        free(qux[i]);
    free(qux);
}

答案 1 :(得分:0)

  

我想做的是将单个指针传递给内存   分配给指针数组。

假设堆上有一些整数,如下所示:

int *integers = (int*)malloc(4 * sizeof(int));

现在假设您在堆上也有一些指针:

int **pointers = (int**)malloc(4*sizeof(int*));

现在让我们将指针分配给整数的地址:

pointers[0] = &integers[0];
pointers[1] = &integers[1];
pointers[2] = &integers[2];
pointers[3] = &integers[3];

在此示例中,pointers是指向(在堆上的)一些整数(也在堆上)的指针数组的指针。您可以随意传递pointers并将其用于其他功能。

或者,如果您希望将指针数组放在堆栈中:

int* pointers[4];
pointers[0] = &integers[0];
pointers[1] = &integers[1];
pointers[2] = &integers[2];
pointers[3] = &integers[3];
int **ppointer = pointers;

现在ppointer也是一个指向一组指向堆中某些整数的指针的指针。请注意,这次,这些指针在堆栈上,而不在堆上。因此,如果您从此函数返回,则它们不在范围内,您可能无法再访问它们。

答案 2 :(得分:0)

您在误解中进行操作。 C和C ++都不能将数组的副本传递给函数,也不能从函数返回数组。

除非它是sizeof或一元&运算符的操作数,或者是用于初始化声明中的字符数组的字符串文字,否则 expression 为类型“ T的N元素数组将被转换(“衰减”)为类型“指向T的指针”的表达式,该表达式的值是第一个元素的地址。

因此,如果您声明一个类似的数组

char *ptrs[N];

并将其传递给函数

foo( ptrs );

表达式 ptrs隐式地从“ char *的N元素数组”转换为“指向char *的指针”,以及{{1} }实际上接收到的是指向数组第一个元素的指针-实际上与编写相同

foo

原型可以写为

foo( &ptrs[0] );

void foo( char **ptrs )

void foo( char *ptrs[] )

在函数参数声明中,数组声明符被“调整”为指针声明符-IOW,void foo( char *ptrs[N] ) T a[N]都被解释为T a[]。但是,在函数参数声明中,这仅是 true。

关于样式...

在C语言中,T *a上的强制转换是不必要的 1 ,在C89下,如果您忘记包含malloc或没有使用stdlib.h,它可以抑制有用的诊断范围内malloc(或callocrealloc)的声明。在C99和更高版本下,您将获得有关没有声明的诊断信息,但是C89仍然允许隐式int声明,并且强制转换会阻止编译器对您大吼大叫,因为int和指针类型是不兼容。之所以提出这一点,是因为MS对C89以后的C语言的支持有些参差不齐。

为了最大程度地减少维护负担,最好避免在malloc调用中明确命名类型。您可以重写

SrcArr = (char **)malloc(999999 * sizeof(char *));

SrcArr = malloc( 999999 * sizeof *SrcArr ); // you sure you need that many elements??!

由于SrcArr的类型为char **,所以表达式 *SrcArr的类型为char *,因此sizeof *SrcArr与{ {1}}。通常,可以编写sizeof (char **)呼叫

malloc

T *p = malloc( N * sizeof *p );

T *p; ... p = malloc( N * sizeof *p ); calloc也是如此。


  1. 这不是C ++中的强制转换,因为C ++不允许从realloc到其他指针类型的隐式转换,但是如果您正在编写C ++,则不应使用void * 无论如何