C语言 为什么字符指针的大小是8,却增加一个字节?

vltsax25  于 2023-10-16  发布在  其他
关注(0)|答案(4)|浏览(141)
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时,它会根据数据类型递增。为什么?这是怎么回事?

im9ewurl

im9ewurl1#

对于输出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 * ),则无法使用指针输出数组。

e0bqpujr

e0bqpujr2#

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

  • T a[10]; T *p = a;定义了一个指向T类型的对象数组的指针p
  • 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
vxf3dgd4

vxf3dgd43#

什么是指针?

简单地说,指针是一种特殊类型的变量,用于保存内存地址,编译器分配的位宽或字节大小可能会因平台而异。例如,如果您使用sizeof操作符获取8位目标的指针大小,则您将获得2个字节,也就是说,指针可以保存最多64 kB的地址值。这是相当大的,足以容纳只有高达64 kB的ROM和高达几个KB的RAM的设备的地址值。
由于编译代码的架构是64位架构,因此系统寄存器的宽度为64位,足以容纳非常大的地址值(264,大于1.8 * 1019)。对于8位字节,这些64位地址占用8个字节。
指针是特殊的对象,所以不能像

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

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

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

指针如何递增

根据指针指向的类型的字节大小,指针会递增。
char类型外,某些类型的大小可能会因平台而异。
现在我们知道了指针以及它们是如何递增的,让我们在一个例子中看看。下面的示例使用GCC编译,并在64位Linux系统中执行。

#include <stdio.h>

int main(void)
{
    char c[3];
    short int si[3];
    int i[3];
    long l[3];
    long long ll[3];
    float f[3];
    double d[3];

    char* cp = c;
    short int* sip = si;
    int* ip = i;
    long* lp = l;
    long long* llp = ll;
    float* fp = f;
    double* dp = d;

    printf("char pointer size is %zu\n", sizeof(cp));
    for (int i = 0; i < 3; i++) {
        printf("%p\n", (void *)cp++);
    }

    printf("\nshort int pointer size is %zu\n", sizeof(sip));
    for (int i = 0; i < 3; i++) {
        printf("%p\n", (void *)sip++);
    }

    printf("\nint pointer size is %zu\n", sizeof(ip));
    for (int i = 0; i < 3; i++) {
        printf("%p\n", (void *)ip++);
    }

    printf("\nlong pointer size is %zu\n", sizeof(lp));
    for (int i = 0; i < 3; i++) {
        printf("%p\n", (void *)lp++);
    }

    printf("\nlong long pointer size is %zu\n", sizeof(llp));
    for (int i = 0; i < 3; i++) {
        printf("%p\n", (void *)llp++);
    }

    printf("\nfloat pointer size is %zu\n", sizeof(fp));
    for (int i = 0; i < 3; i++) {
        printf("%p\n", (void *)fp++);
    }

    printf("\ndouble pointer size is %zu\n", sizeof(dp));
    for (int i = 0; i < 3; i++) {
        printf("%p\n", (void *)dp++);
    }

    cp = NULL;
    sip = NULL;
    ip = NULL;
    lp = NULL;
    llp = NULL;
    fp = NULL;
    dp = NULL;

    return 0;
}

示例的输出如下:

char pointer size is 8
0x7ffc1d893c79
0x7ffc1d893c7a
0x7ffc1d893c7b

short int pointer size is 8
0x7ffc1d893c72
0x7ffc1d893c74
0x7ffc1d893c76

int pointer size is 8
0x7ffc1d893c64
0x7ffc1d893c68
0x7ffc1d893c6c

long pointer size is 8
0x7ffc1d893c40
0x7ffc1d893c48
0x7ffc1d893c50

long long pointer size is 8
0x7ffc1d893c20
0x7ffc1d893c28
0x7ffc1d893c30

float pointer size is 8
0x7ffc1d893c14
0x7ffc1d893c18
0x7ffc1d893c1c

double pointer size is 8
0x7ffc1d893bf0
0x7ffc1d893bf8
0x7ffc1d893c00

总结

正如您在输出中看到的,所有指针都具有相同的大小,即使它们指向不同的类型。此大小可能因平台而异。
然而,指针的值根据它们所指向的类型而递增或递减。同样,某些类型的大小可能会因平台而异。

  • 根据@chqrlie的合理评论进行了一些更新 *
yzckvree

yzckvree4#

这是因为一个字符占用1个字节,而一个指向字符的指针是一个指针,而不是一个字符或其他东西,这意味着它存储了一个内存地址,所以它占用8个字节。此外,所有类型的指针在您的机器上都是8字节。

相关问题