在C / C ++中,char * arrayName 是指向指针的指针还是指向指针的指针?
我理解多维数组作为指针的指针,但也许我错了?
例如,我虽然:
char * var
= char var[]
char ** var
= char* var[]
或char var[][]
char *** var
= char var[][][]
或char* var[][]
或char** var[]
这不正确吗? 我很困惑,因为我在简单的教科书示例中看到了char * [] []演员作为char **。
我粘贴了下面的例子。 任何人都可以为我清除这个吗? 谢谢!
/* A simple dictionary. */ #include #include #include /* list of words and meanings */ char *dic[][40] = { "atlas", "A volume of maps.", "car", "A motorized vehicle.", "telephone", "A communication device.", "airplane", "A flying machine.", "", "" /* null terminate the list */ }; int main(void) { char word[80], ch; char **p; do { puts("\nEnter word: "); scanf("%s", word); p = (char **)dic; /* find matching word and print its meaning */ do { if(!strcmp(*p, word)) { puts("Meaning:"); puts(*(p+1)); break; } if(!strcmp(*p, word)) break; p = p + 2; /* advance through the list */ } while(*p); if(!*p) puts("Word not in dictionary."); printf("Another? (y/n): "); scanf(" %c%*c", &ch); } while(toupper(ch) != 'N'); return 0; }
C的规则如下:
6.3.2.1左值,数组和函数指示符
…
3除非它是sizeof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则将类型为”array of type”的表达式转换为类型为”指针的表达式键入”指向数组对象的初始元素,而不是左值。 如果数组对象具有寄存器存储类,则行为未定义。
C ++的语言有点不同:
4.2数组到指针的转换[conv.array]
1“NT的数组”或“T的未知边界数组”类型的左值或右值可以转换为“指向T的指针”的右值。 结果是指向数组的第一个元素的指针。
…
8.3.4数组[dcl.array]
…
7多维数组遵循一致的规则。 如果E是秩i × j ×…× k的n维数组,那么出现在表达式中的E被转换为指向具有等级j ×…× k的( n -1)维数组的指针。 如果将*运算符(由于下标而显式或隐式)应用于此指针,则结果是指向的( n -1)维数组,该数组本身立即转换为指针。
所以以下都适用:
Declaration Expression Type Decays to ----------- ---------- ---- --------- T a[N] a T [N] T * &a T (*)[N] *a T a[i] T T a[M][N] a T [M][N] T (*)[N] &a T (*)[M][N] *a T [N] T * a[i] T [N] T * &a[i] T (*)[N] *a[i] T a[i][j] T T a[M][N][O] a T [M][N][O] T (*)[M][N] &a T (*)[M][N][O] *a T [M][N] T (*)[N] a[i] T [M][N] T (*)[N] &a[i] T (*)[M][N] *a[i] T [N] T * a[i][j] T [N] T * &a[i][j] T (*)[N] *a[i][j] T a[i][j][k] T
对于更高维数组,该模式应该是清晰的。
那么让我们分析你的字典:
/* list of words and meanings */ char *dic[][40] = { "atlas", "A volume of maps.", "car", "A motorized vehicle.", "telephone", "A communication device.", "airplane", "A flying machine.", "", "" /* null terminate the list */ };
这不会按照你想要的方式设置你的字典; 你基本上把它设置为一个包含40个指向char的1元素数组。 如果你想要一组字符串对,那么声明应如下所示:
char *dic[][2] = { {"atlas", "A volume of maps"}, {"car", "A motorized vehicle"}, {"telephone", "A communication device"}, {"airplane" , "A flying machine"}, {NULL, NULL} // empty strings and NULLs are different things. };
dic
的类型是“指向char的2元素数组的5元素数组”或char *[5][2]
。 按照上面的规则,表达式dic
应该衰减为char *(*)[2]
– 指向char *(*)[2]
的指针的2元素数组的指针。
搜索此字典的函数将如下所示:
char *definition(char *term, char *(*dictionary)[2]) // *NOT* char ***dictionary { while ((*dictionary)[0] != NULL && strcmp((*dictionary)[0], term) != 0) dictionary++; return (*dictionary)[1]; }
你会从你的主要function中调用它
char *def = definition(term, dic);
请注意,我们必须在函数中的*dictionary
表达式周围使用括号。 数组下标operator []
优先级高于dereference运算符*
,我们不想直接下标到dictionary
,我们想要下标到dictionary
指向的数组中。
我理解多维数组作为指针的指针,但也许我错了?
是的,你错了。 数组和指针之间存在差异。 数组可以衰减成指针,但指针不会携带有关它所指向的数组的大小或配置的状态。 不要将这种自动衰减与数组和指针相同的想法混淆 – 它们不是。
char **
是指向包含字符指针的内存块的指针,字符指针本身指向字符的内存块。 char [][]
是包含字符的单个内存块。
如果你有一个char **
并使用ptr[x][y]
访问它,编译器会将其更改为*(*(ptr + x)+y)
。 如果你有char [][]
,编译器会将arr[x][y]
更改为*(ptr + rowLength*y + x)
。 ( 注意 :我在Xs和Ys的顺序上没有110%的正面,但是这对于我在这里提出的点并不重要)注意,给定指针,编译器不知道任何关于大小的信息或者数组的维度,如果将指针视为多维数组,则无法确定实际地址。
char *dic[][40]
是一个大小为char *dic[][40]
的数组数组,包含字符指针 。 因此它根本不符合您的作业。
p = (char **)dic;
< - 这就是演员阵容不好的原因。 编译器告诉你,你真正想对dic
做的事没有任何意义。 但是,由于您可以将指针强制转换为任何其他指针,因此即使尝试以这种方式读取数据也会导致未定义的行为,转换也会成功。
你需要参考“右边的规则” 。 或者你可以在这里消除大部分C-ish声明
所以,
char *p[2][3]
被解析为
p是一个包含2个元素的数组,其中每个元素是一个包含3个元素的数组,这样每个元素都是一个指向字符的指针。([]绑定比*更强)
char (*p)[2][3]
被解析为
“p是指向2个元素char数组的指针,其中每个元素都是3个元素的char数组。” (括号绑定最强)
没有看太多细节,但我认为作者依赖于c布局像这样的2d字符串数组:
连续内存中的键,值,键,值,键,值。 然后遍历这个数组作为1d数组的字符串p = (char **)dic;
这是C的美丽和潜在问题之一 – 它具有很多低级别的function,但是你可以使用合适的代码保护自己以防止副作用。
我和*
和[]
组合的记忆规则之一是main
的签名。 作品! 🙂
你的dic
是一个40元素数组的数组,每个元素都是一个指向char
的指针。
#include #include using namespace std; template< class Type, unsigned N > void tellMeAbout( Type const (&)[N] ) { cout << "Well, it's an array of " << typeid( Type ).name() << ".\n"; } int main() { char *dic[][40] = { 0 }; tellMeAbout( dic ); }
使用Visual C ++我得到...
好吧,这是一个char * [40]的数组。
干杯&hth。,
- 阿尔夫