C指针问题

我真的对指针如何工作感到困惑。 我正在尝试编写简短的小程序,这些程序将完全阐明它们的工作方式,并且我遇到了一些麻烦。 例如:

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 

显然这段代码不正确,否则我不会在论坛上投票:)

我只是从一本书中解决了这个问题,有人可以简单解释这个概念吗?

首先,这里的c不是指针,它是一个数组。 在某些情况下,数组可以像指针一样使用,但它们不是同一个东西。 特别是,您可以使用*c (就好像它是一个指针)来访问第一个位置的值,但由于c实际上不是指针,因此您无法使用c++更改c指向的位置。

其次,你误解了*意味着什么。 它不仅仅是使用指针时使用的装饰。 作为运营商,它意味着“取消引用”,即让我访问所指向的内容。 因此,当您操作指针本身(例如,通过递增它)而不操纵指向的数据时,您不需要使用它。

这是你可能想要的:

 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 char* p_c; // Creates a character pointer that we will use to refer into the c array p_c = &c[0]; // Assign the address of the first element of the c array to the p_c pointer. // This could also be "p_c = c", taking advantage of the fact that in this // is one of the circumstances in which an array can be treated as if it were // a pointer to its first element *p_c = 'a'; //sets c[0] to 'a' p_c++; //moves the pointer to c[1] (note no *) *p_c = 'b'; //sets c[1] to 'b' p_c++; //moves the pointer to c[2] (note no *) *p_c = '\0' //sets c[2] to the terminating zero 

c不是指针,它是一个数组。 虽然数组的名称在大多数数组上下文中衰减为指针,但您不能将数组名称视为可修改的指针。 衰变的结果只是暂时的(技术上是一个右值 )。

因此,您无法将++应用于数组的名称。 如果要增加指针,请使用指针:

 char *d = c; 

指针和数组在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示例

单步执行调试器中的程序并检查所有内容的值有助于我理解指针。 还可以在白板上绘制大量图片,以巩固您的理解。 对我来说真正巩固它的是学习组装并从头开始提出MIPS ……

尝试在调试器中单步执行此操作,并在白板上绘制一些图表以跟踪执行情况。

 #include  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 +  | 0xbf94393d | +------------------------------------------+ 

当你访问c_arr[0] ,你正在使用表格中的第一行。 请注意, c_ptr的值为表中顶行的地址 。 当你说*c_ptr ,你告诉CPU使用0xbf94393d作为操作的地址。 所以*c_ptr = 'z'有点像说“嘿,转到0xbf94393d并在那里留下’z’” – 在这条街上,地址非常大。

数组的名称可以被视为指向它的第一个元素的指针,尽管它是一个常量指针,因此它不能指向任何其他位置。 所以不允许使用c++

尝试

 c++; *c = 'b'; c++; *c = '\0'; 

*运算符正在尝试取消引用指针。 您需要做的就是移动指针,然后完成任务。