关于指针

时间:2018-08-11 13:48:53

标签: c pointers

因此,我已经尝试了一段时间的指针,并提出了一些问题。在下面的代码中,首先,当我打印每个内存地址时:
pHours ++-pHours-pHours + sizeof(char),得到以下结果: 1989086632-1989086636-1989086636.
pHours ++的值不应该比pHours的值大而不是小4个单位(顺便说一句,C通常不分配1个字节而不是4个字节来存储字符吗?) 此外,为什么pHours + sizeof(char)的值与pHours的相同?在我下面编写的代码中,很明显,加上sizeof(char)确实会更改指针指向的地址,因为当我在函数的最后一个打印语句中忽略它时,会遇到分段错误(* nHours没有价值)。
另外,为什么当我编写nHours ++时却出现分段错误,而对skata(skata ++)或pHours(pHours ++)却如此却没有呢?
哦,还有两件事。 Visual Studio的编译器给我一个错误,因为在使用它们之前不初始化* nHours和* skata,但允许使用在线编译器进行初始化。为什么这是VS中的强制性做法?
另外,为什么最好使用格式字符串%p而不是%d来引用内存地址?
目前为止就这样了。先感谢您! :)

#include <stdio.h>

#define MinutesPerHour 60

void ConvertTimeToHM(int time, int *pHours, int *pMinutes);

int main()
{
    int time, hours, minutes;
    printf("Enter a time duration in minutes: ");
    scanf("%d", &time);
    ConvertTimeToHM(time, &hours, &minutes);
    printf("HH:MM format: %d:%02d\n", hours, minutes);
    return 0;
}

void ConvertTimeToHM(int time, int *pHours, int *pMinutes)
{
    *pHours = time / MinutesPerHour;
    int *nHours, *skata, *kHours;
    *pMinutes = time % MinutesPerHour;
    //nHours = pHours;
    //nHours++;
    skata++;
    printf("%d %d %d\n", pHours++, pHours, pHours + sizeof(char));
    skata = nHours + 3 * sizeof(char);
    *skata = 19;
    printf("%d\n", *(nHours + 3 * sizeof(char)));
}

2 个答案:

答案 0 :(得分:0)

  

此外,为什么pHours + sizeof(char)的值与pHours的值相同?

因为您在pHours语句中通过尝试更新++ 来调用了未定义行为,并且在没有中间序列的情况下将其值用于计算点(也用于错误的转换说明符)。不能保证函数参数从左到右进行求值,也不能保证%f的结果立即得到求值。

将其分解为多个语句,您将看到不同的结果。

  

Visual Studio的编译器给我一个错误,因为在使用它们之前不初始化* nHours和* skata,但允许使用在线编译器进行初始化。为什么在VS中必须这样做?

要求编译器发布语法错误和约束违规的诊断-除此之外,这取决于各个供应商。

  

此外,为什么最好使用格式字符串%p而不是%d来引用内存地址?

出于相同的原因,我们将%s用作双精度,将%c用作字符串,将{{1}}用作单个字符-因为语言规范是这样说的。指针不是整数;尽管它们可能在许多系统上都有完整的表示形式,但这并不能保证。

答案 1 :(得分:0)

  

pHours ++的值不应为4个单位

我不确定您正在阅读哪本书,但是不管它是什么,它都不适合您...

给出int *p;p+0等效于&p[0]p+1等效于&p[1],依此类推。从逻辑上讲,(p + 1) - (p + 0)必须为1,但是1并不表示char;它表示一个int,因为这就是您要指向的类型。

另一方面,如果要在pHours之前和之后将char *强制转换为void *(或pHours),则可能可以看到更多与您期望的类似的东西……但是可能也可能是1,例如CHAR_BIT是32。

  

(顺便说一句,C通常不分配1个字节而不是4个字节来存储字符吗?)

是的,在C语言中,char总是 恰好占据一个字节,因此sizeof (char)总是 1 ... 但是字节不必是八位字节;您可以使用CHAR_BIT获得字节中的位数,根据C标准,该位数必须至少为8,并且必须为1632一些系统,所以...

  

比pHours的值大而不是小的?

p++的值是递增前的p。递增后,++p的值为p

  

此外,为什么pHours + sizeof(char)的值与pHours的值相同?

在下面的代码中,您将调用未定义的行为,因此不应过多地阅读它。

printf("%d %d %d\n", pHours++, pHours, pHours + sizeof(char));

您需要注意,未指定参数的评估顺序,因此下一个参数中的pHours++后跟pHours是未定义的行为(即,可能导致不可预测的结果,包括崩溃,安全性受到损害,等等)……还告诉printf打印一个int值,然后传递一个int *值:这也是UB。您可能打算写:printf("%p", (void *) pHours++); printf("%p %p\n", pHours, pHours + sizeof (char));

  

此外,为什么在编写nHours ++时出现分段错误,而对skata(skata ++)或pHours(pHours ++)执行相同操作却没有?

未定义的行为并不意味着会产生细分错误;这将是定义的行为。未定义的行为意味着...好吧,让我们从未定义开始...缺乏定义...对吗?这意味着它没有任何意义。我要在这里说的是您的代码的行为没有任何意义。允许 进行段错误,但实际上不是必不可少的

这说明了缓冲区溢出,不一定导致段错误;他们可能会因为产品正常运行多年而没有被注意,并且没有人对其进行探测,因此,黑客发现了一个可疑的段错误,看起来可疑的缓冲区溢出……并设法渗透到您的代码库中……不,段错误肯定不是 not 在这里是必需的...但是没有任何逻辑上的行为。

您从哪里得到期望?我担心您实际上可能不是正在阅读,但是是猜测 ...请告诉我您不是猜测 ...这并不安全那样学习C!相信我;我去过那里并且做到了,而您也收到了一些与我相同的误解。如果我是对的,而您不是在读一本书,那就考虑出去找一本K&R2E的副本。记得做练习。


  

Visual Studio的编译器给我一个错误,因为在使用它们之前不初始化* nHours和* skata,但允许使用在线编译器进行初始化。为什么在VS中必须这样做?

Visual Studio正在检测使用未初始化值的未定义行为...并且在这一点上,Visual Studio不需要遵循C标准,因为您已经超出了C领域,因此可以在那时停止编译。


  

此外,为什么最好使用格式字符串%p而不是%d来引用内存地址?

%p告诉printff期望一个void *参数,这很重要,因为printff需要知道它正在对void *参数进行操作... %d告诉printff期望一个int参数...两种类型具有不同的用例。不要混在一起。如果传递了错误的参数类型,这是未定义的行为。