我真的对指针的工作方式感到困惑。我正在尝试编写简短的小程序,这些程序将完全阐明它们的工作方式,并且我遇到了一些麻烦。例如:
char c[3]; //Creates an array of 3 bytes - the first 2 bytes can be used for characters and the 3rd would need to be used for the terminating zero
*c = 'a'; //sets c[0] to 'a'
*c++; //moves the pointer to c[1]
*c = 'b'; //sets c[1] to 'b'
*c++; //moves the pointer to c[2]
*c = '\0' //sets c[2] to the terminating zero
显然这段代码不正确,否则我不会在论坛上投票:)
我只是从一本书中解决这个问题,有人可以简单地解释这个概念吗?
答案 0 :(得分:15)
c
不是指针,它是一个数组。虽然数组的名称在大多数数组上下文中衰减为指针,但您不能将数组名称视为可修改的指针。衰变的结果只是暂时的(技术上是 rvalue )。
因此,您无法将++
应用于数组名称。如果要增加指针,请使用指针:
char *d = c;
答案 1 :(得分:6)
首先,c
这里不是指针,它是一个数组。在某些情况下,数组可以像指针一样使用,但它们不是同一个东西。特别是,您可以使用*c
(就像它是指针一样)来访问第一个位置的值,但由于c
实际上不是指针,因此您无法更改{{1使用c
指出。
其次,你误解了c++
的含义。它不仅仅是使用指针时使用的装饰。作为操作员,它意味着“取消引用”,即让我访问所指向的内容。因此,当您操纵指针本身(例如,通过递增它)而不操纵指向的数据时,您无需使用它。
以下是您可能想要的内容:
*
答案 2 :(得分:3)
指针和数组在C中是不同的事物。混淆的根源是数组被转换(衰变,正如标准所指定的那样)到最轻微挑衅的指针。它被称为“衰变”,因为它丢失了一些关于数组类型的信息(即它的大小)。
让我们看看......
void f( char* p );
char c_array [3]; // define an array
char *c_ptr = c_array; // define a pointer and set it to point at the beginning of the array
// here array "decays" to pointer
*c_ptr = '1';
assert(c_array[0] == '1');
assert(c_ptr[0] == '1'); // this works too... in fact, operator [] is defined
// for pointers, not arrays, so in the line above array
// decays to pointer too.
++c_ptr; // move the pointer
//++c_array; // -- this won't compile, you can't move the array
*c_ptr++ = '2';
*c_ptr = '\0';
assert(c_array[1] == '2');
assert(c_array[2] == 0);
assert(sizeof(c_array) == 3); // no decay here!
assert(sizeof(c_ptr) == sizeof(void*)); // a pointer is just a pointer
f(c_array); // array-to-pointer decay, again
// now, what happens here?
void g( char param [100] )
{
++param; // it works!
// you can't pass an array as a parameter by value.
// The size in the parameter declaration is ignored; it's just a comment.
// param is a pointer.
assert(sizeof(param) == sizeof(void*));
// yes, it's just a pointer
assert(*param == '2'); // in the call below
}
g(c_array); // array-to-pointer decay, again
希望这会有所帮助。
(请注意,我为了说明而混合了声明和语句。你必须重新排列一些东西才能使它成为一个有效的C程序)。
编辑:添加了sizeof examples
答案 3 :(得分:1)
逐步调试调试器中的程序并检查所有内容的值有助于我理解指针。还可以在白板上绘制大量图片,以巩固您的理解。真正巩固它的对象是学习组装并从头开始制作MIPS ......
尝试在调试器中逐步执行此操作,并在白板上绘制一些图表以跟踪执行情况。
#include <stdio.h>
int main()
{
char c_arr[3] = {'a', 'b', '\0'}; // Array of 3 chars.
char* c_ptr = c_arr; // Now c_ptr contains the address of c_arr.
// What does it mean that c_ptr "contains the address of c_arr"?
// Underneath all this talk of "pointers" and "arrays", it's all
// just numbers stored in memory or registers. So right now, c_ptr is
// just a number stored somewhere in your computer.
printf("%p\n", c_ptr);
// I got `0xbf94393d`. You'll get something different each time you run it.
// That number (0xbf94393d) is a particular memory location. If you
// want to use the contents of that memory location, you use the *
// operator.
char ch = *c_ptr;
// Now ch holds the contents of whatever was in memory location 0xbf94393d.
// You can print it.
printf("%c\n", ch);
// You should see `a`.
// Let's say you want to work with the next memory location. Since
// the pointer is just a number, you can increment it with the ++ operator.
c_ptr++;
// Let's print it to see what it contains.
printf("%p\n", c_ptr);
// I got 0xbf94393e. No surprises here, it's just a number -- the
// next memory location after what was printed above.
// Again, if we want to work with the value we can use the *
// operator. You can put this on the left side of an assignment
// to modify the memory location.
*c_ptr = 'z';
// Since c_ptr was pointing to the middle of our array when we
// performed that assignment, we can inspect the array to see
// the change.
printf("%c\n", c_arr[1]);
// Again, c_ptr is just a number, so we can point it back to
// where it was. You could use -- for this, but I'll show -=.
c_ptr -= 1;
// We can also move by more than one. This will make the pointer
// contain the address of the last memory location in the array.
c_ptr = c_ptr + 2;
return 0;
}
这是我对照片的尝试。这个盒子是你电脑的记忆。内存中的每个位置都分配了一个号码,我们称该号码为地址。
++++++++++++++++++++++++++++++++++++++++++++
| NAME | ADDRESS | VALUE |
+=========+==============+=================+
| c_arr | 0xbf94393d | 'a' |
| | 0xbf94393e | 'b' |
| | 0xbf94393f | '\0' |
+---------+--------------+-----------------+
| c_ptr + <someaddr> | 0xbf94393d |
+------------------------------------------+
当您访问c_arr[0]
时,您正在使用表格中的第一行。请注意,c_ptr
的值为表中顶行的地址。当您说*c_ptr
时,您告诉CPU使用0xbf94393d
作为要操作的地址。所以*c_ptr = 'z'
有点像说“嘿,转到0xbf94393d并在那里留下'z'” - 在这条街上,地址非常大。
答案 4 :(得分:1)
数组的名称可以被视为指向它的第一个元素的指针,尽管它是一个常量指针,因此它不能指向任何其他位置。因此不允许使用c++
。
答案 5 :(得分:0)
尝试
c++;
*c = 'b';
c++;
*c = '\0';
*运算符正在尝试取消引用指针。您需要做的就是移动指针,然后完成任务。