C语言 C语言中的**是做什么的
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35021521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What does ** do in C language
提问by James
I'm new to C with a good background in java and I'm trying to understand pointers and arrays.
我是 C 新手,具有良好的 Java 背景,我正在尝试理解指针和数组。
I know that subscript operator[]is part of an array definition, so:
我知道下标operator[]是数组定义的一部分,所以:
int numbers[] = {1,3,4,5};
would create a integer array, which would be represented in memory as 16 bytes, 4 lots of 4 bytes:
将创建一个整数数组,它将在内存中表示为 16 个字节,4 个 4 个字节:
numbers[0] = 1, address 0061FF1C
numbers[1] = 3, address 0061FF20
numbers[2] = 4, address 0061FF24
numbers[3] = 5, address 0061FF28
However, when it comes to pointers my knowledge starts to break down, so if I was to create a pointer to the array numbers I would do the following:
然而,当涉及到指针时,我的知识开始崩溃,所以如果我要创建一个指向数组数字的指针,我将执行以下操作:
int *pNumbers = &numbers[0];
which would look something like this:
看起来像这样:
And I'm guessing it would be of size 4 bytes?
我猜它的大小是 4 个字节?
However the **I read as "pointer to a pointer" which makes no sense to me, why would anyone want a pointer to a pointer, surely if a->b->c then a->c would suffice? I know I'm missing something, and it must have something to do with arrays as argvcan be of type char[ ]or char **as seen bellow:
然而,**我读作“指向指针的指针”对我来说毫无意义,为什么有人想要一个指向指针的指针,当然如果 a->b->c 那么 a->c 就足够了?我知道我错过了一些东西,它必须与数组有关,argv可以是类型char[ ]或char **如下所示:
int main(int argc, char **argv){}
So:
所以:
- what is this (
**)? - what use does it have?
- how is it represented in memory?
- 这是什么(
**)? - 它有什么用?
- 它在内存中是如何表示的?
采纳答案by Vlad from Moscow
In C arguments are passed by values. For example if you have an integer varaible in main
在 C 中,参数通过值传递。例如,如果您在 main 中有一个整数变量
int main( void )
{
int x = 10;
//...
and the following function
和以下功能
void f( int x )
{
x = 20;
printf( "x = %d\n", x );
}
then if you call the function in main like this
那么如果你像这样在 main 中调用函数
f( x );
then the parameter gets the value of variable xin main. However the parameter itself occupies a different extent in memory than the argument. So any changes of the parameter in the function do not influence to the original variable in main because these changes occur in different memory extent.
然后参数获取xmain中变量的值。然而,参数本身在内存中所占的空间与参数不同。所以函数中参数的任何变化都不会影响main中的原始变量,因为这些变化发生在不同的内存范围内。
So how to change the varible in main in the function?
那么如何改变函数中main中的变量呢?
You need to pass a reference to the variable using pointers.
您需要使用指针传递对变量的引用。
In this case the function declaration will look like
在这种情况下,函数声明看起来像
void f( int *px );
and the function definition will be
并且函数定义将是
void f( int *px )
{
*px = 20;
printf( "*px = %d\n", *px );
}
In this case it is the memory extent occupied by the original variable xis changed because within the function we get access to this extent using the pointer
在这种情况下,原始变量占用的内存范围x发生了变化,因为在函数中我们可以使用指针访问该范围
*px = 20;
Naturally the function must be called in main like
自然地,必须在 main 中调用该函数,例如
f( &x );
Take into account that the parameter itself that is the pointer pxis as usual a local variable of the function. That is the function creates this variable and initializes it with the address of variable x.
考虑到px作为指针的参数本身通常是函数的局部变量。那就是函数创建这个变量并用变量的地址初始化它x。
Now let's assume that in main you declared a pointer for example the following way
现在让我们假设您在 main 中声明了一个指针,例如以下方式
int main( void )
{
int *px = malloc( sizeof( int ) );
//..
And the function defined like
和定义的函数
void f( int *px )
{
px = malloc( sizeof( int ) );
printf( "px = %p\n", px );
}
As parameter pxis a local variable assigning to it any value does not influence to the original pointer. The function changes a different extent of memory than the extent occupied by the original pointer pxin main.
由于参数px是一个局部变量,分配给它的任何值都不会影响原始指针。该函数更改的内存范围px与 main 中原始指针占用的范围不同。
How to change the original pointer in the function? Just pass it by reference!
如何更改函数中的原始指针?只需通过引用传递它!
For example
例如
f( &px );
//...
void f( int **px )
{
*px = malloc( sizeof( int ) );
printf( "*px = %p\n", *px );
}
In this case the value stored in the original pointer will be changed within the function because the function using dereferencing access the same memory extent where the original pointer was defined.
在这种情况下,存储在原始指针中的值将在函数内更改,因为使用解引用的函数访问定义原始指针的相同内存范围。
回答by kirk roerig
Q: what is this (**)?
问:这是什么(**)?
A: Yes, it's exactly that. A pointer to a pointer.
A:是的,正是这样。指向指针的指针。
Q: what use does it have?
问:它有什么用?
A: It has a number of uses. Particularly in representing 2 dimensional data (images, etc). In the case of your example char** argvcan be thought of as an array of an array of chars. In this case each char*points to the beginning of a string. You could actually declare this data yourself explicitly like so.
答:它有多种用途。特别是在表示二维数据(图像等)方面。在您的示例的情况下,char** argv可以将其视为chars数组的数组。在这种情况下,每个都char*指向字符串的开头。您实际上可以像这样自己明确声明这些数据。
char* myStrings[] = {
"Hello",
"World"
};
char** argv = myStrings;
// argv[0] -> "Hello"
// argv[1] -> "World"
When you access a pointer like an array the number that you index it with and the size of the element itself are used to offset to the address of the next element in the array. You could also access all of your numbers like so, and in fact this is basically what C is doing. Keep in mind, the compiler knows how many bytes a type like intuses at compile time. So it knows how big each step should be to the next element.
当您访问像数组一样的指针时,您使用它索引的数字和元素本身的大小用于偏移到数组中下一个元素的地址。您也可以像这样访问所有数字,实际上这基本上就是 C 正在做的事情。请记住,编译器知道一个类型int在编译时使用了多少字节。所以它知道每一步到下一个元素应该有多大。
*(numbers + 0) = 1, address 0x0061FF1C
*(numbers + 1) = 3, address 0x0061FF20
*(numbers + 2) = 4, address 0x0061FF24
*(numbers + 3) = 5, address 0x0061FF28
The *operator is called the dereference operator. It is used to retrieve the value from memory that is pointed to by a pointer. numbersis literally just a pointer to the first element in your array.
该*运算符称为解引用运算符。它用于从指针指向的内存中检索值。numbers实际上只是指向数组中第一个元素的指针。
In the case of my example myStringscould look something like this assuming that a pointer/address is 4 bytes, meaning we are on a 32 bit machine.
在我的示例中myStrings,假设指针/地址为 4 个字节,这可能看起来像这样,这意味着我们在 32 位机器上。
myStrings = 0x0061FF14
// these are just 4 byte addresses
(myStrings + 0) -> 0x0061FF14 // 0 bytes from beginning of myStrings
(myStrings + 1) -> 0x0061FF18 // 4 bytes from beginning of myStrings
myStrings[0] -> 0x0061FF1C // de-references myStrings @ 0 returning the address that points to the beginning of 'Hello'
myStrings[1] -> 0x0061FF21 // de-references myStrings @ 1 returning the address that points to the beginning of 'World'
// The address of each letter is 1 char, or 1 byte apart
myStrings[0] + 0 -> 0x0061FF1C which means... *(myStrings[0] + 0) = 'H'
myStrings[0] + 1 -> 0x0061FF1D which means... *(myStrings[0] + 1) = 'e'
myStrings[0] + 2 -> 0x0061FF1E which means... *(myStrings[0] + 2) = 'l'
myStrings[0] + 3 -> 0x0061FF1F which means... *(myStrings[0] + 3) = 'l'
myStrings[0] + 4 -> 0x0061FF20 which means... *(myStrings[0] + 4) = 'o'
回答by Some programmer dude
The traditional way to write the argvargument is char *argv[]which gives more information about what it is, an array of pointers to characters (i.e. an array of strings).
写argv参数的传统方法是char *argv[]提供更多关于它是什么的信息,一个指向字符的指针数组(即一个字符串数组)。
However, when passing an array to a function it decays to a pointer, leaving you with a pointer to pointer to char, or char **.
但是,当将数组传递给函数时,它会衰减为一个指针,从而为您留下一个指向char、 或 的指针char **。
Of course, double asterisks can also be used when dereferencing a pointer to a pointer, so without the added context at the end of the question there are two answers to the question what **means in C, depending on context.
当然,在取消引用指向指针的指针时也可以使用双星号,因此如果没有在问题末尾添加上下文**,根据上下文,在 C 中意味着什么的问题有两个答案。
To continue with the argvexample, one way to get the first character of the first element in argvwould be to do argv[0][0], oryou could use the dereference operator twice, as in **argv.
继续该argv示例,获取第一个元素的第一个字符的一种方法argv是 do argv[0][0],或者您可以两次使用取消引用运算符,如**argv.
Array indexing and dereferencing is interchangeable in most places, because for any pointer orarray pand index ithe expression p[i]is equivalent to *(p + i). And if iis 0then we have *(p + 0)which can be shortened to *(p)which is the same as *p.
数组索引和解引用在大多数地方是可以互换的,因为对于任何指针或数组p和索引i,表达式p[i]等价于*(p + i)。如果i是0那么我们有*(p + 0)which 可以缩短为*(p)which 与 相同*p。
As a curiosity, because p[i]is equivalent to *(p + i)and the commutative propertyof addition, the expression *(p + i)is equal to *(i + p)which leads to p[i]being equal to i[p].
作为一个好奇,因为p[i]等价于*(p + i)和加法的交换性质,表达式*(p + i)等于*(i + p)导致p[i]等于i[p]。
Finally a warning about excessive use of pointers, you might sometime hear the phrase three-star programmer, which is when one uses three asterisks like in ***(like in a pointer to a pointer to a pointer). But to quote from the link
最后是关于过度使用指针的警告,您有时可能会听到短语三星级程序员,即使用三个星号,如 in ***(如在指向指针的指针中)。但是从链接中引用
Just to be clear: Being called a ThreeStarProgrammer is usually not a compliment
需要明确的是:被称为三星程序员通常不是恭维
And another warning: An array of arrays is notthe same as a pointer to a pointer(Link to an old answer of mine, which also shows the memory layout of a pointer to a pointer as a substitute of an array of arrays.)
和另一条警告:数组的数组是不一样的指针的指针(链接到旧答案矿,其还示出了指针的指针作为数组的数组的一个替代的存储器布局。)
回答by haccks
**in declaration represents pointer to pointer. Pointer is itself a data type and like other data types it can have a pointer.
**in 声明表示指向指针的指针。指针本身是一种数据类型,与其他数据类型一样,它也可以有一个指针。
int i = 5, j = 6; k = 7;
int *ip1 = &i, *ip2 = &j;
int **ipp = &ip1;
Pointer to pointer are useful in case of allocating dynamic 2D array. To allocate a 10x10 2D array (may not be contiguous)
在分配动态二维数组的情况下,指向指针的指针很有用。分配一个 10x10 的二维数组(可能不连续)
int **m = malloc(sizeof(int *)*10;
for(int i = 0; i < 10; i++)
m[i] = malloc(sizeof(int)*10
It is also used when you want to change the value of a pointer through a function.
当您想通过函数更改指针的值时,也会使用它。
void func (int **p, int n)
{
*p = malloc(sizeof(int)*n); // Allocate an array of 10 elements
}
int main(void)
{
int *ptr = NULL;
int n = 10;
func(&ptr, n);
if(ptr)
{
for(int i = 0; i < n; i++)
{
ptr[i] = ++i;
}
}
free(ptr);
}
Further reading: Pointer to Pointer.
进一步阅读:指向指针的指针。
回答by ash
Consider if you have a table of pointers - such as a table of strings (since strings in "C" are handled simply as pointers to the first character of the string).
考虑一下您是否有一个指针表 - 例如一个字符串表(因为“C”中的字符串被简单地处理为指向字符串第一个字符的指针)。
Then you need a pointer to the first pointer in the table. Hence the "char **".
然后你需要一个指向表中第一个指针的指针。因此,“字符**”。
If you have an inline table with all the values, like a two-dimensional table of integers, then it's entirely possible to get away with only one level of indirection (i.e. just a simple pointer, like "int *"). But when there is a pointer in the middle that needs to be dereferenced to get to the end result, that creates a second level of indirection, and then the pointer-to-pointer is essential.
如果你有一个包含所有值的内联表,比如一个二维整数表,那么完全有可能只使用一级间接(即只是一个简单的指针,如“int *”)。但是,当中间有一个指针需要取消引用才能获得最终结果时,这就创建了第二级间接引用,然后指针到指针是必不可少的。
Another clarification here. In "C", dereferencing via pointer notation (e.g. "*ptr") vs array index notation (e.g. ptr[0]) has little difference, other than the obvious index value in array notation. The only time asterisk vs brackets really matters is when allocating a variable (e.g. int *x; is very different than int x[1]).
这里的另一个澄清。在“C”中,通过指针符号(例如“*ptr”)与数组索引符号(例如ptr[0])取消引用几乎没有区别,除了数组符号中明显的索引值。星号与括号真正重要的唯一时间是分配变量时(例如 int *x; 与 int x[1] 非常不同)。
回答by John Bollinger
Of your int *example you say
你的int *例子你说
And I'm guessing it would be of size 4 bytes?
我猜它的大小是 4 个字节?
Unlike Java, C does not specify the exact sizes of its data types. Different implementations can and do use different sizes (but each implementation must be consistent). 4-byte ints are common these days, but ints can be as small two bytes, and nothing inherently limits them to four. The size of pointers is even less specified, but it usually depends on the hardware architecture at which the C implementation is targeted. The most common pointer sizes are four bytes (typical for 32-bit architectures) and eight bytes (common for 64-bit architectures).
与 Java 不同,C 不指定其数据类型的确切大小。不同的实现可以并且确实使用不同的大小(但每个实现必须一致)。4 字节ints 现在很常见,但ints 可以小到两个字节,并且没有任何内在的限制它们为四个。指针的大小甚至更少指定,但它通常取决于 C 实现所针对的硬件体系结构。最常见的指针大小是四字节(32 位架构的典型值)和八字节(64 位架构的常见值)。
what is this (**)?
这是什么 (**)?
In the context you present, it is part of the type designator char **, which describes a pointer to a pointer to char, just as you thought.
在您呈现的上下文中,它是类型指示符的一部分,正如您所想的那样char **,它描述了指向指向的指针的指针char。
what use does it have?
它有什么用?
More or less the same uses as a pointer to any other data type. Sometimes you want or need to access a pointer value indirectly, just like you may want or need to access a value of any other type indirectly. Also, it's useful for pointing to (the first element of) an array of pointers, which is how it is used in the second parameter to a C main()function.
或多或少用作指向任何其他数据类型的指针。有时您希望或需要间接访问指针值,就像您可能希望或需要间接访问任何其他类型的值一样。此外,它对于指向(的第一个元素)一个指针数组很有用,这就是它在 Cmain()函数的第二个参数中的使用方式。
In this particular case, each char *in the pointed-to array itself points to one of the program's command-line arguments.
在这种特殊情况下,char *指向数组本身中的每一个都指向程序的命令行参数之一。
how is it represented in memory?
它在内存中是如何表示的?
C does not specify, but typically pointers to pointers have the same representation as pointers to any other type of value. The value it points to is simply a pointer value.
C 没有指定,但通常指向指针的指针与指向任何其他类型值的指针具有相同的表示形式。它指向的值只是一个指针值。
回答by hqt
**stands for pointer to pointer as you know the name. I will explain each of your question:
**如您所知,代表指向指针的指针。我将解释您的每个问题:
what is this (**)?
这是什么 (**)?
Pointer to Pointer. Sometime people call double pointer. For example:
指向指针的指针。有时人们称双指针。例如:
int a = 3;
int* b = &a; // b is pointer. stored address of a
int**b = &b; // c is pointer to pointer. stored address of b
int***d = &c; // d is pointer to pointer to pointer. stored address of d. You get it.
how is it represented in memory?
它在内存中是如何表示的?
cin above example is just a normal variable and has same representation as other variables (pointer, int ...). Memory size of variable c same as band it depends on platform. For example, 32-bit computer, each variable address includes 32bit so size will be 4 bytes (8x4=32 bit) On 64-bit computer, each variable address will be 64bit so size will be 8 bytes (8x8=64 bit).
c在上面的例子中只是一个普通变量,与其他变量(指针,int ...)具有相同的表示形式。变量 c 的内存大小与b平台相同。例如,32 位计算机,每个变量地址包括 32 位,因此大小为 4 个字节(8x4=32 位) 在 64 位计算机上,每个变量地址为 64 位,因此大小为 8 个字节(8x8=64 位)。
what use does it have?
它有什么用?
There are many usages for pointer to pointer, depends on your situation. For example, here is one example I learned in my algorithm class. You have a linked list. Now, you want to write a method to change that linked list, and your method may changed head of linked list. (Example: remove one element with value equals to 5, remove head element, swap, ...). So you have two cases:
指向指针的指针有很多用法,取决于您的情况。例如,这是我在算法课上学到的一个例子。你有一个链表。现在,您要编写一个方法来更改该链表,并且您的方法可能会更改链表的头部。(例如:删除一个值等于 5 的元素,删除头元素,交换,...)。所以你有两种情况:
1. If you just pass a pointer of head element. Maybe that head element will be removed, and this pointer doesn't valid anymore.
1. 如果你只是传递一个 head element 的指针。也许那个头元素将被删除,这个指针不再有效。
2. If you pass pointer of pointer of head element.In case your head element is removed, you meet no problem because the pointer of pointer still there. It just change values of another head node.
2.如果你传递头元素的指针的指针。如果您的头元素被删除,您不会遇到任何问题,因为指针的指针仍然存在。它只是改变另一个头节点的值。
You can reference here for above example: pointer to pointer in linked list
您可以在此处参考上述示例:指向链表中指针的指针
Another usage is using in two-dimensional array. C is different from Java. Two dimensional array in C, in fact just a continuous memory block. Two dimensional array in Java is multi memory block (depend on your row of matrix)
另一种用法是在二维数组中使用。C 与 Java 不同。C中的二维数组,实际上只是一个连续的内存块。Java中的二维数组是多内存块(取决于您的矩阵行)
Hope this help :)
希望这有帮助:)
回答by John Bode
First of all, remember that C treats arrays very differently from Java. A declaration like
首先,请记住 C 对数组的处理与 Java 非常不同。像这样的声明
char foo[10];
allocates enough storage for 10 charvalues and nothing else(modulo any additional space to satisfy alignment requirements); no additional storage is set aside for a pointer to the first element or any other kind of metadata such as array size or element class type. There's no object fooapart from the array elements themselves1. Instead, there's a rule in the language that anytime the compiler sees an array expressionthat isn't the operand of the sizeofor unary &operator (or a string literal used to initialize another array in a declaration), it implicitly converts that expressionfrom type "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array.
为 10 个char值分配足够的存储空间,没有别的(以任何额外空间为模以满足对齐要求);没有为指向第一个元素的指针或任何其他类型的元数据(例如数组大小或元素类类型)预留额外的存储空间。foo除了数组元素本身1之外,没有任何对象。相反,语言中有一条规则,当编译器看到一个数组表达式不是sizeof或 一元运算&符的操作数(或用于在声明中初始化另一个数组的字符串文字)时,它会隐式地将该表达式从类型“ T" to " 指针的N 元素数组T",表达式的值是数组第一个元素的地址。
This has several implications. First is that when you pass an array expression as an argument to a function, what the function actually receives is a pointer value:
这有几个含义。首先,当您将数组表达式作为参数传递给函数时,函数实际接收的是一个指针值:
char foo[10];
do_something_with( foo );
...
void do_something_with( char *p )
{
...
}
The formal parameter pcorresponding to the actual parameter foois a pointer to char, not an array of char. To make things confusing, C allows do_something_withto be declared as
实参p对应的形参foo是指向 的指针char,而不是 的数组char。为了使事情变得混乱,C 允许do_something_with声明为
void do_something_with( char p[] )
or even
甚至
void do_something_with( char p[10] )
but in the case of function parameter declarations, T p[]and T p[N]are identical to T *p, and all three declare pas a pointer, not an array2. Note that this is only true for function parameter declarations.
但在函数参数声明的情况下,T p[]和T p[N]与 相同T *p,并且所有三个声明p为指针,而不是数组2。请注意,这仅适用于函数参数声明。
The second implication is that the subscript operator []can be used on pointer operands as well as array operands, such as
第二个含义是下标运算符[]可用于指针操作数以及数组操作数,例如
char foo[10];
char *p = foo;
...
p[i] = 'A'; // equivalent to foo[i] = 'A';
The final implication leads to one case of dealing with pointers to pointers - suppose you have an array of pointers like
最后的含义导致处理指向指针的指针的一种情况 - 假设您有一个指针数组,例如
const char *strs[] = { "foo", "bar", "bletch", "blurga", NULL };
strsis a 5-element array of const char *3; however, if you pass it to a function like
strs是有5个元素的数组const char *3; 但是,如果您将其传递给类似的函数
do_something_with( strs );
then what the function receives is actually a pointer to a pointer, not an array of pointers:
那么函数接收到的实际上是一个指向指针的指针,而不是一个指针数组:
void do_something_with( const char **strs ) { ... }
Pointers to pointers (and higher levels of indirection) also show up in the following situations:
指向指针(以及更高级别的间接)的指针也会出现在以下情况中:
- Writing to a parameter of pointer type:Remember that C passes all parameters by value; the formal parameter in the function definition is a different object in memory than the actual parameter in the function call, so if you want the function to update the value of the actual parameter, you must pass a pointerto that parameter:
Now suppose we replace the typevoid foo( T *param ) // for any type T { *param = new_value(); // update the object param *points to* } void bar( void ) { T x; foo( &x ); // update the value in x }Twith the pointer typeR *, then our code snippet looks like this:
Same semantics - we're updating the value contained invoid foo( R **param ) // for any type R * { ... *param = new_value(); // update the object param *points to* ... } void bar( void ) { R *x; foo( &x ); // update the value in x }x. It's just that in this case,xalready has a pointer type, so we must pass a pointer to the pointer. This can be extended to higher levels of direction:void foo( Q ****param ) // for any type Q *** { ... *param = new_value(); // update the object param *points to* ... } void bar( void ) { Q ***x; foo( &x ); // update the value in x } - Dynamically-allocated multi-dimensional arrays: One common technique for allocating multi-dimensional arrays in C is to allocate an array of pointers, and for each element of that array allocate a buffer that the pointer points to:
This can be extended to higher levels of indirection, so you have have types likeT **arr; arr = malloc( rows * sizeof *arr ); // arr has type T **, *arr has type T * if ( arr ) { for ( size_t i = 0; i < rows; i++ ) { arr[i] = malloc( cols * sizeof *arr[i] ); // arr[i] has type T * if ( arr[i] ) { for ( size_t j = 0; j < cols; j++ ) { arr[i][j] = some_initial_value(); } } } }T ***andT ****, etc.
- 写入指针类型的参数:记住C通过值传递所有参数;函数定义中的形参与函数调用中的实参在内存中是不同的对象,因此如果您希望函数更新实参的值,则必须传递指向该参数的指针:
现在假设我们用void foo( T *param ) // for any type T { *param = new_value(); // update the object param *points to* } void bar( void ) { T x; foo( &x ); // update the value in x }T指针 type替换类型R *,那么我们的代码片段看起来像这样:
相同的语义 - 我们正在更新void foo( R **param ) // for any type R * { ... *param = new_value(); // update the object param *points to* ... } void bar( void ) { R *x; foo( &x ); // update the value in x }x. 只是在这种情况下,x已经有了一个指针类型,所以我们必须传递一个指向该指针的指针。这可以扩展到更高级别的方向:void foo( Q ****param ) // for any type Q *** { ... *param = new_value(); // update the object param *points to* ... } void bar( void ) { Q ***x; foo( &x ); // update the value in x } - 动态分配的多维数组:在 C 中分配多维数组的一种常用技术是分配一个指针数组,并为该数组的每个元素分配一个指针指向的缓冲区:
这可以扩展到更高级别的间接,所以你有像T **arr; arr = malloc( rows * sizeof *arr ); // arr has type T **, *arr has type T * if ( arr ) { for ( size_t i = 0; i < rows; i++ ) { arr[i] = malloc( cols * sizeof *arr[i] ); // arr[i] has type T * if ( arr[i] ) { for ( size_t j = 0; j < cols; j++ ) { arr[i][j] = some_initial_value(); } } } }T ***andT ****等类型。
1. This is part of why array expressions may not be the target of an assignment; there's nothing to assign anything to.
This is a holdover from the B programming language from which C was derived; in B, a pointer is declared as
auto p[].Each string literal is an array of
char, but because we are not using them to initialize individual arrays ofchar, the expressions are converted to pointer values.
这是从 C 派生而来的 B 编程语言的延续;在 B 中,一个指针被声明为
auto p[]。每个字符串文字都是 的数组
char,但因为我们没有使用它们来初始化 的单个数组char,所以表达式被转换为指针值。
回答by James
I think I'm going to add my own answer in here as well as everyone has done an amazing job but I was really confused at what the point of a pointer to a pointer was. The reason why I came up with this is because I was under the impression that all the values except pointers, were passed by value, and pointers were passed by reference. See the following:
我想我将在这里添加我自己的答案,因为每个人都做了出色的工作,但我真的很困惑指向指针的意义是什么。我想出这个的原因是因为我的印象是除了指针之外的所有值都是按值传递的,而指针是按引用传递的。请参阅以下内容:
void f(int *x){
printf("x: %d\n", *x);
(*x)++;
}
void main(){
int x = 5;
int *px = &x;
f(px);
printf("x: %d",x);
}
would produce:
会产生:
x: 5
x: 6
This made my think (for some reason) that pointers were passed by reference as we are passing in the pointer, manipulating it and then breaking out and printing the new value. If you can manipulate a pointer in a function... why have a pointer to a pointer in order to manipulate the pointer to begin with!
这让我认为(出于某种原因)指针是通过引用传递的,因为我们传入指针,操作它,然后打破并打印新值。如果您可以在函数中操作指针……为什么要使用指向指针的指针来操作指针!
This seemed wrong to me, and rightly so because it would be silly to have a pointer to manipulate a pointer when you can already manipulate a pointer in a function. The thing with C though; is everything is passed by value, even pointers. Let me explain further using some pseudo values instead of the addresses.
这对我来说似乎是错误的,这是正确的,因为当您已经可以在函数中操作指针时,使用指针来操作指针是愚蠢的。不过,C 的事情;是一切都按值传递的,甚至是三分球。让我使用一些伪值而不是地址来进一步解释。
//this generates a new pointer to point to the address so lets give the
//new pointer the address 0061FF28, which has the value 0061FF1C.
void f(int 0061FF1C){
// this prints out the value stored at 0061FF1C which is 5
printf("x: %d\n", 5);
// this FIRST gets the value stored at 0061FF1C which is 5
// then increments it so thus 6 is now stored at 0061FF1C
(5)++;
}
void main(){
int x = 5;
// this is an assumed address for x
int *px = 0061FF1C;
/*so far px is a pointer with the address lets say 0061FF24 which holds
*the value 0061FF1C, when passing px to f we are passing by value...
*thus 0061FF1C is passed in (NOT THE POINTER BUT THE VALUE IT HOLDS!)
*/
f(px);
/*this prints out the value stored at the address of x (0061FF1C)
*which is now 6
*/
printf("x: %d",6);
}
My main misunderstanding of pointers to pointers is the pass by value vs pass by reference. The original pointer was not passed into the function at all, so we cannot change what address it is pointing at, only the address of the new pointer (which has the illusion of being the old pointer as its pointing to the address the old pointer was pointing to!).
我对指针的主要误解是按值传递与按引用传递。原始指针根本没有传递到函数中,所以我们不能改变它指向的地址,只有新指针的地址(它有旧指针的错觉,因为它指向旧指针所在的地址)指向!)。
回答by moonboy
It is a pointer to a pointer. If you are asking why you would want to use a pointer to a pointer, here is a similar thread that answers that in a variety of good ways.
它是一个指向指针的指针。如果您问为什么要使用指向指针的指针,这里有一个类似的线程,它以各种好方法回答了这个问题。


