繁体   English   中英

C 中的指针,我很困惑

[英]Pointers in C, I'm so confused

目前我在 C 指针上关注这个pdf。 下面的代码是为了演示,但让我难以置信。 首先,我对指向 arrays 的指针的理解是,它们在堆 memory 中使用 memory 地址进行初始化,因此数组中第一个元素的地址是: ptr = &my_array[0]; /* and */ ptr = my_array; ptr = &my_array[0]; /* and */ ptr = my_array; 是一回事。 我对这段代码的第一个问题是他创建了一个不指向 memory 地址的指针。 我认为指针初始化通常会涉及 & 并且 pA 的值将是数组第一个元素的 memory 地址,但是当他将指针打印到屏幕上时,整个字符串都会打印出来。 为什么? 最重要的是,当我在 pA 上放另一个 * 时,它会打印数组的第一个字符。 为什么? 最重要的是,他在 *pA 和 *pB 上使用了 ++,这对我来说毫无意义,因为 output 显示 *pA 是数组中的第一个字符,而不是 memory 地址。

抱歉,这个概念对我来说很难理解。 PDF 是在解释指针方面做得不好还是我严重误解了什么?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char strA[80] = "A string to be used for demonstration purposes";
char strB[80];

int main(int argc, char *argv[]){
    char *pA; /* a pointer to type character */
    char *pB; /* another pointer to type character */
    puts(strA); /* show string A */
    pA = strA; /* point pA at string A */
    puts(pA); /* show what pA is pointing to */
    pB = strB; /* point pB at string B */
    putchar('\n'); /* move down one line on the screen */
    printf("\n%c\n", *pA);
    while(*pA != '\0') /* line A (see text) */
    {
        *pB++ = *pA++; /* line B (see text) */
    }
    *pB = '\0'; /* line C (see text) */
    puts(strB); /* show strB on screen */
    return 0;
}

Output:

A string to be used for demonstration purposes
A string to be used for demonstration purposes


A
A string to be used for demonstration purposes

编辑:感谢大家的帮助:),对不起noobie问题。 我阅读了 Stephen G. Kochan 的 C 中的编程,其中关于指针的精彩部分帮助很大。

char strA[80] = "A string to be used for demonstration purposes";

这会在可执行文件的全局部分中产生 80 个字符长的空间——它不是动态分配的,因此不需要释放。 如果 strA 用作指针,则它与您期望的一样等价于&strA[0]

这 80 个字符用等号右侧的字符串填充 - 包括字符串末尾的终止字符。 该终止字符非常重要,因为这就是您在数组中找到可打印数据的结尾的方式。

puts(strA); /* show string A */

当您puts(strA)时,function 打印从传入的地址到该终止字符的每个字符 - function 内部有一个循环。

pA = strA; /* point pA at string A */
puts(pA); /* show what pA is pointing to */

然后pA&strA[0]的值填充,然后当puts(pA); 被调用时,function 接收到它上次接收到的相同地址,因此它执行与上次相同的操作:它打印从传入的地址到该终止字符的每个字符。

printf("\n%c\n", *pA);
while(*pA != '\0') /* line A (see text) */

*字符为您提供指针位置的内容 - 因此*strA提供与strA[0]相同的内容 - 字符串的第一个字符。 并且*pA*strA相同,因为它们都指向同一个地址。

*pB++ = *pA++; /* line B (see text) */

*pA++让您感到困惑的原因是因为您不知道是先完成*还是++ 发生的情况是: pA++增加指针并返回它的原始值。 然后*获取指针的原始值并给出其内容 - pA 最初指向的字符。

根据 C 标准(6.3.2.1 Lvalues、arrays 和 function 代号)

3 除非它是 sizeof 运算符或一元 & 运算符的操作数,或者是用于初始化数组的字符串字面量,否则类型为 ''array of type'' 的表达式将转换为类型为 ''pointer 的表达式键入指向数组 object 的初始元素且不是左值的'' 如果数组 object 具有寄存器存储 class,则行为未定义。

所以这两个赋值语句

ptr = &my_array[0]; 

ptr = my_array;

是等价的,因为用作初始化器的数组指示符my_array被隐式转换为指向其第一个元素的指针。

在 C 中,字符串是字符 arrays ,其中包含以零终止字符'\0'结尾的字符序列。

例如,字符串文字“Hello”存储为具有此字符序列的字符数组

{ 'H', 'e', 'l', 'l', 'o', '\0' }

function puts专门用于 output 字符串。

它是通过以下方式声明的

int puts(const char *s);

function 的调用

puts(strA);
puts(pA)

是等价的,因为在第一次调用中用作参数的数组指示符strA被隐式转换为指向其第一个元素的指针。

在此调用中取消引用指针

 printf("\n%c\n", *pA);

你会得到指针指向的 object。 当指针pA指向数组strA的第一个字符时,输出该字符。

作为弗拉德回答的后续行动,这很好,我只想添加一小段代码,这真的有助于我理解指针。 我发现做出预测然后编写代码并进行观察直到我理解为止真的很有帮助。

[ttucker@zim stackoverflow]$ cat ptr.c 
#include <stdio.h>

int main() {
    char *foo = "stuff";
    while (*foo != '\0') {
        printf("%lu: %c (%d), %lu\n", &foo, *foo, *foo, foo);
        foo++;
    }
    return 0;
}


[ttucker@zim stackoverflow]$ gcc -o ptr ptr.c


[ttucker@zim stackoverflow]$ ./ptr 
140730183740528: s (115), 94216543457284
140730183740528: t (116), 94216543457285
140730183740528: u (117), 94216543457286
140730183740528: f (102), 94216543457287
140730183740528: f (102), 94216543457288

# A second execution is included to show that the memory addresses change.

[ttucker@zim stackoverflow]$ ./ptr 
140723360085232: s (115), 94198997999620
140723360085232: t (116), 94198997999621
140723360085232: u (117), 94198997999622
140723360085232: f (102), 94198997999623
140723360085232: f (102), 94198997999624

首先,我对指向 arrays 的指针的理解是,它们在堆 memory 中使用 memory 地址进行初始化,因此数组中第一个元素的地址是: ptr = &my_array[0]; /* and */ ptr = my_array; ptr = &my_array[0]; /* and */ ptr = my_array; 是一回事。

唯一一次“堆” memory 发挥作用是当您使用malloccallocrealloc或在幕后调用它们的库函数时。 pApB占用与在 scope 中声明的任何其他类型的变量相同的 memory。

但是当他将指针打印到屏幕上时,整个字符串就会打印出来。

puts function 获取字符串中第一个字符的地址并“遍历”字符串,打印每个字符,直到看到字符串终止符,有点像

void myputs( const char *str ) // str points to the first character in a 0-terminated string
{
  while ( *str )         // while we haven't seen the string terminator
    putchar( *str++ );   // print the current character and advance the pointer    
}

最重要的是,他在 *pA 和 *pB 上使用了 ++,这对我来说毫无意义,因为 output 显示 *pA 是数组中的第一个字符,而不是 memory 地址。

线

*pB++ = *pA++;

大致相当于写:

*pB = *pA;
pB = pB + 1;
pA = pA + 1;

后缀++比一元*具有更高的优先级,因此*pA++被解析为*(pA++) - 你取消引用pA++结果 pA++的结果是pA的当前值,并且作为副作用pA递增。 由于pApB是指针,加 1 使它们指向序列中的下一个object ,不一定是下一个字节(尽管在这种特殊情况下,下一个 object下一个字节)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM