为什么 char 指针的大小是 8,但会增加一个字节?

问题描述 投票:0回答:4
void main() {
    char var = 10;
    char *ptr = &var;
    
    printf("Pointer address before increment:%p\n", ptr);
    printf("sizeof(ptr):%d\n", sizeof(ptr));
    ptr++;
    printf("Pointer address after increment:%p\n", ptr);
    printf("sizeof(ptr):%d\n", sizeof(ptr));
}

输出:

Pointer address before increment:0x7fffb997144f
sizeof(ptr):8
Pointer address after increment:0x7fffb9971450
sizeof(ptr):8

为什么

char
指针只增加一个字节?它的大小是8,对吗? 当声明
ptr
时,编译器为其分配 8 个字节。当我们将其递增
1
时,它会根据数据类型递增。为什么?这是如何运作的?

c pointers sizeof pointer-arithmetic
4个回答
2
投票

对于初学者输出

size_t
类型的值,您需要使用转换说明符
zu
而不是
d

printf("sizeof(ptr):%zu\n",sizeof(ptr));
                    ^^^

自增指针指向它所指向的对象之后的内存。也就是说,类型为

T *
的指针的值会增加值
sizeof( T )

考虑访问数组元素的例子。

T a[N];

表达式

a[i]
的计算结果类似于
*( a + i )
。所以指针的值会增加
i * sizeof( T )

这称为指针算术,

对于

char
类型的对象的大小,则根据 C 标准,
sizeof( char )
始终等于
1

另请考虑以下演示程序。

#include <stdio.h>

int main( void )
{
    char s[] = "Hello";

    for ( const char *p = s; *p != '\0'; ++p )
    {
        putchar( *p );
    }
    putchar( '\n' );
}

它的输出是

Hello

如果指针

p
增加了值
sizeof( char * )
,则无法使用指针输出数组。


1
投票

对于指针算术,重要的不是指针的大小,而是它指向的类型的大小:

  • T a[10]; T *p = a;
    定义了一个指向
    p
    类型的对象数组的指针
    T
  • p
    包含
    a
    第一个元素的内存地址。
  • 下一个元素的地址再远
    sizeof(T)
    个字节,因此将指针
    p
    加 1 会使内存地址增加
    sizeof(*p)

这是修改后的版本:

#include <stdio.h>

int main() {
    char char_array[2] = "a";
    char *char_ptr = char_array;
    
    printf("sizeof(char_ptr): %zu\n", sizeof(char_ptr));
    printf("char_ptr before increment: %p\n", (void *)char_ptr);
    printf("sizeof(*char_ptr): %zu\n", sizeof(*char_ptr));
    char_ptr++;
    printf("char_ptr after increment: %p\n", (void *)char_ptr);

    int int_array[2] = { 1, 2 };
    int *int_ptr = int_array;
    
    printf("\nsizeof(int_ptr): %zu\n", sizeof(int_ptr));
    printf("int_ptr before increment: %p\n", (void *)int_ptr);
    printf("sizeof(*int_ptr): %zu\n", sizeof(*int_ptr));
    int_ptr++;
    printf("int_ptr after increment: %p\n", (void *)int_ptr);

    return 0;
}

输出(64 位):

sizeof(char_ptr): 8
char_ptr before increment: 0x7fff52c1f7ce
sizeof(*char_ptr): 1
char_ptr after increment: 0x7fff52c1f7cf

sizeof(int_ptr): 8
int_ptr before increment: 0x7fff52c1f7c0
sizeof(*int_ptr): 4
int_ptr after increment: 0x7fff52c1f7c4

输出(32位):

sizeof(char_ptr): 4
char_ptr before increment: 0xbffc492e
sizeof(*char_ptr): 1
char_ptr after increment: 0xbffc492f

sizeof(int_ptr): 4
int_ptr before increment: 0xbffc4930
sizeof(*int_ptr): 4
int_ptr after increment: 0xbffc4934

0
投票

什么是指针?

简单来说,指针是一种特殊类型的变量,用于保存内存地址,编译器分配的位宽或字节大小可能会因平台而异。例如,如果在 8 位架构中使用

sizeof
运算符调整指针大小,则在大多数设备中,您将获得 2 个字节,也就是说,指针最多可以容纳 64kB 的地址值。这在逻辑上足够大,足以容纳仅具有最多 64kB ROM 和最多几 kB RAM 的设备的地址值。

由于编译代码的体系结构是 64 位体系结构,因此系统寄存器是 64 位宽,并且足够宽以容纳非常大的地址值 (2 * 10^64)。由于它足够大,它自然会大小为 64 位/8 字节。

如上所述,指针是特殊对象,因此您不能分配类似的常量

int* ptr = 0x7fffb997144f; // Compilers will not allow this

编译器不会允许这样做,因为指针不是常规类型的变量。因此,为了分配一个常量地址值,您必须将其转换为指针,如下例所示:

int* ptr = (int*) 0x7fffb997144f; // Compilers will allow this

指针如何递增

这取决于指针指向的类型的字节大小。那就是;

  • 1 代表
    char
    类型
  • 2 代表
    short int
    类型
  • 4 代表
    long
    类型
  • 8 代表
    long long
    类型

某些字体大小(例如

int
float
类型)可能会因平台而异。

现在我们了解了指针以及它如何递增,让我们为上面的每种类型举一个例子。假设每个示例的起始地址是 0x7fffb997144f。

  1. 适用于
    char
    类型
char vars[5];
char* ptr = vars;   // 0x7fffb997144f
ptr++;              // 0x7fffb9971450
ptr++;              // 0x7fffb9971451
  1. 适用于
    short int
    类型
short int vars[5];
short int* ptr = vars;  // 0x7fffb997144f
ptr++;              // 0x7fffb9971451
ptr++;              // 0x7fffb9971453
  1. 适用于
    long
    类型
long vars[5];
long* ptr = vars;   // 0x7fffb997144f
ptr++;              // 0x7fffb9971454
ptr++;              // 0x7fffb9971458
  1. 适用于
    long long
    类型
long long vars[5];
long long* ptr = vars;  // 0x7fffb997144f
ptr++;              // 0x7fffb9971458
ptr++;              // 0x7fffb997145f

0
投票

那是因为一个字符占用1个字节,而指向字符的指针是一个指针,而不是字符或其他东西,也就是说它存储的是内存地址,所以它占用8个字节。而且各种指针在你的机器上都是8字节。

© www.soinside.com 2019 - 2024. All rights reserved.