我不太喜欢指针。我知道足以获取指向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。
答案 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
(或calloc
或realloc
)的声明。在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
也是如此。
realloc
到其他指针类型的隐式转换,但是如果您正在编写C ++,则不应使用void *
无论如何。