C语言(指针)test_3_4

C语言(指针)test_3_4

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

数组名的理解
数组名是数组首元素(第一个元素)的地址
但是有2个例外:
1. sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
2. &数组名 - 数组名表示整个数组,取出的是整个数组的地址
除此之外,所以的数组名是数组首元素(第一个元素)的地址。


int main()
{
	int a[] = { 1,2,3,4 };//数组有几个元素?

	printf("%zd\n", sizeof(a));//16 -- sizeof(数组名)的场景
	printf("%zd\n", sizeof(a + 0));//a是首元素的地址-类型是int*, a+0 还是首元素的地址,是地址大小就是4/8
	printf("%zd\n", sizeof(*a));//a是首元素的地址,*a就是首元素,大小就是4个字节
	*a == a[0] == *(a+0)
	printf("%zd\n", sizeof(a + 1));//a是首元素的地址,类型是int*,a+1跳过1个整型,a+1就是第二个元素的地址,4/8
	printf("%zd\n", sizeof(a[1]));//a[1]就是第二个元素,大小4个字节
	printf("%zd\n", sizeof(&a));//&a是数组的地址,数组的地址也是地址,是地址大小就是4/8个字节
	printf("%zd\n", sizeof(*&a));//1. *& 互相抵消了,sizeof(*&a) = sizeof(a) -16
	2. &a 是数组的地址,类型是int(*)[4],对数组指针解引用访问的是数组, 计算的是数组的大小 -16
	
	printf("%zd\n", sizeof(&a + 1));//&a+1是跳过整个数组后的那个位置的地址,是地址就是4/8个字节
	printf("%zd\n", sizeof(&a[0])); //首元素的地址,大小4/8个字节
	printf("%zd\n", sizeof(&a[0] + 1));//&a[0] + 1 -- 数组第二个元素的地址,大小是4/8个字节

	return 0;
}



int main()
{
	char arr[] = { 'a','b','c','d','e','f' };

	printf("%d\n", sizeof(arr));//数组名单独放在sizeof内部了,计算的是数组的大小,单位是字节-6
	printf("%d\n", sizeof(arr + 0));//arr是数组名表示首元素的地址,arr+0还是首元素的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,大小就是1个字节
	*arr -- arr[0] - *(arr+0)
	printf("%d\n", sizeof(arr[1]));//arr[1] 是第二个元素,大小也是1个字节
	printf("%d\n", sizeof(&arr));//&arr 是数组地址,数组的地址也是地址,大小是4/8个字节
	&arr -- char (*)[6]
	printf("%d\n", sizeof(&arr + 1));//&arr+1, 跳过整个数组,指向了数组后边的空间,4/8个字节
	printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,是地址就是4/8字节

	return 0;
}

#include <string.h>

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));//arr是首元素的地址,数组中没有\0,就会导致越界访问,结果就是随机的
	printf("%d\n", strlen(arr + 0));//arr+0是数组首元素的地址,数组中没有\0,就会导致越界访问,结果就是随机的
	printf("%d\n", strlen(*arr));//arr是首元素的地址,*arr是首元素,就是'a','a'的ascii码值是97
	就相当于把97作为地址传递给了strlen,strlen得到的就是野指针, 代码是有问题的
	printf("%d\n", strlen(arr[1]));//arr[1]--'b'--98,传给strlen函数也是错误的
	printf("%d\n", strlen(&arr));//&arr是数组的地址,起始位置是数组的第一个元素的位置,随机值 x
	printf("%d\n", strlen(&arr + 1));//随机值 x-6
	printf("%d\n", strlen(&arr[0] + 1));//从第2个元素开始向后统计的,得到的也是随机值 x-1

	return 0;
}




int main()
{
	char arr[] = "abcdef";
	printf("%d\n", sizeof(arr));//arr是数组名,单独放在sizeof内部,计算的是数组总大小,是7个字节
	printf("%d\n", sizeof(arr + 0));//arr表示数组首元素的地址,arr+0还是首元素的地址,是地址就是4/8
	printf("%d\n", sizeof(*arr));//arr表示数组首元素的地址,*arr就是首元素,大小是1字节
	printf("%d\n", sizeof(arr[1]));//arr[1]是第二个元素,大小1个字节
	printf("%d\n", sizeof(&arr));//&arr是数组的地址,是地址就是4/8
	printf("%d\n", sizeof(&arr + 1));//&arr是数组的地址,+1跳过整个数组,还是地址,是地址就是4/8个字节
	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0] + 1是第二个元素的地址,大小是4/8个字节

	return 0;
}


#include <string.h>

int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//6
	printf("%d\n", strlen(arr + 0));//arr首元素的地址,arr+0还是首元素的地址,向后在\0之前有6个字符
	printf("%d\n", strlen(*arr));//'a'-97, 出错
	printf("%d\n", strlen(arr[1]));//'b'-98, 出错
	printf("%d\n", strlen(&arr));//&arr是数组的地址,也是从数组第一个元素开始向后找,6
	&arr -- char (*)[7]
	size_t strlen(const char* s);

	printf("%d\n", strlen(&arr + 1));//随机值
	printf("%d\n", strlen(&arr[0] + 1));//5

	return 0;
}




int main()
{
	const char * p = "abcdef";

	printf("%d\n", sizeof(p));//p是指针变量,我们计算的是指针变量的大小,4/8个字节
	printf("%d\n", sizeof(p + 1));//p + 1是b的地址,是地址大小就是4/8个字节
	printf("%d\n", sizeof(*p));//p的类型是const char*, *p就是char类型了,1个字节
	printf("%d\n", sizeof(p[0]));//1. p[0] --> *(p+0)--> *p --> 'a',大小是1字节
	2. 把常量字符串想象成数组,p可以理解为数组名,p[0], 就是首元素

	printf("%d\n", sizeof(&p));//取出的是p的地址,地址的大小是4/8个字节
	printf("%d\n", sizeof(&p + 1));//&p + 1是跳过p指针变量后的地址,是地址就是4/8个字节
	printf("%d\n", sizeof(&p[0] + 1));//4/8 &p[0]-取出字符串首字符的地址,+1是第二个字符的地址,大小是4/8个字节

	return 0;
}


int main()
{
	char* p = "abcdef";
	printf("%d\n", strlen(p));//6
	printf("%d\n", strlen(p + 1));//5
	printf("%d\n", strlen(*p));//*p就是'a'-97,err
	printf("%d\n", strlen(p[0]));//p[0]--> *(p+0)--> *p //err
	printf("%d\n", strlen(&p));//&p是指针变量p的地址,和字符串"abcdef"关系就不大了
	从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以答案是随机值
	printf("%d\n", strlen(&p + 1));//随机值

	printf("%d\n", strlen(&p[0] + 1));//&p[0]-取出字符串首字符的地址,+1是第二个字符的地址, 5

	return 0;
}


int main()
{
	int a[3][4] = { 0 };
	printf("%d\n", sizeof(a));//a是数组名,单独放在sizeof内部,计算的是数组的大小,单位是字节 - 48 = 3*4*sizeof(int)
	printf("%d\n", sizeof(a[0][0]));//a[0][0] 是第一行第一个元素,大小4个字节 
	printf("%d\n", sizeof(a[0]));//a[0]第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小 16 个字节
	printf("%d\n", sizeof(a[0] + 1));//a[0]第一行的数组名,但是a[0]并没有单独放在sizeof内部,所以这里的数组名a[0]就是
	数组首元素的地址,就是&a[0][0],+1后是a[0][1]的地址,大小是4/8个字节

	printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1)表示第一行第二个元素,大小就是4
	printf("%d\n", sizeof(a + 1));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是
	第一行的地址,a+1,跳过一行,指向了第二行,a+1是第二行的地址,a+1是数组指针,是地址大小就是4/8个字节

	printf("%d\n", sizeof(*(a + 1)));//1.a+1是第二行的地址,*(a+1)就是第二行,计算的是第二行的大小 - 16
	2. *(a + 1) == a[1], a[1]是第二行的数组名,sizeof(*(a + 1))就相当于sizeof(a[1]),意思是把第二行的数组名单独放在
	sizeof内部,计算的是第二行的大小
	printf("%d\n", sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]取出的就是数组的地址,就是第一行的地址
	&a[0]+1 就是第二行的地址,是地址大小就是4/8个字节
	printf("%d\n", sizeof(*(&a[0] + 1)));//*(&a[0] + 1)意思是对第二行的地址解引用,访问的就是第二行,大小是16字节
	printf("%d\n", sizeof(*a));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是
	第一行的地址,*a就是第一行,计算的就是第一行的大小,16字节
	*a == *(a+0) == a[0]
	printf("%d\n", sizeof(a[3]));//a[3]无需真实存在,仅仅通过类型的推断就能算出长度
	a[3]是第四行的数组名,单独放在sizeof内部,计算的是第四行的大小,16个字节

	sizeof(int);//4
	sizeof(3 + 5);//4

	return 0;
}

#include <stdio.h>

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int* ptr = (int*)(&a + 1);
    printf("%d,%d", *(a + 1), *(ptr - 1));
    return 0;
}


在X86(32位)环境下
假设结构体的大小是20个字节
程序输出的结果是啥?
struct Test
{
    int Num;
    char* pcName;
    short sDate;
    char cha[2];
    short sBa[4];
} * p = (struct Test*)0x100000;

指针+-整数

int main()
{
    printf("%p\n", p + 0x1);
    printf("%p\n", (unsigned long)p + 0x1);
    printf("%p\n", (unsigned int*)p + 0x1);

    return 0;
}



#include <stdio.h>

int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };//初始化
    int* p;
    p = a[0];
    printf("%d", p[0]);
    return 0;
}











 

 

<think>嗯,用户问的是在C语言中,已知变量test_1等于0x040FA997,如何计算test_1[0]的值,以及指针和数组的关系。首先,我需要理清指针和数组在C语言中的联系和区别。 用户提到test_1被赋值为一个十六进制地址,可能是一个指针变量。比如,假设test_1是一个指针,那么test_1[0]就是解引用该指针指向的内存位置的值。但具体类型会影响如何解析该地址处的数据。例如,如果是char指针test_1[0]就是该地址的一个字节;如果是int指针,可能会读取4个字节(取决于系统)。 不过,用户的问题可能存在一个误区,因为如果test_1是一个整型变量而不是指针,直接使用test_1[0]会导致编译错误,因为数组下标操作符需要指针类型。因此,首先要明确test_1的类型。根据引用[1],typedef可以定义数组类型,但这里用户没有提到typedef,可能test_1被声明为指针或数组? 假设test_1是一个指针变量,存储了0x040FA997这个地址。那么test_1[0]等同于*(test_1 + 0),即访问该地址处的值。但具体如何计算这个值,需要考虑指针的类型。例如,如果是int*,则读取sizeof(int)字节的数据,并解释为整数。 但用户的问题可能更基础,需要解释指针和数组的关系。在C语言中,数组名在大多数情况下会退化为指向其首元素的指针。所以,数组和指针在访问元素时有相似性,比如arr[i]等价于*(arr + i)。 另外,引用[3]提到变量的地址和内容,这里test_1的值是地址,而test_1[0]是访问该地址的内容。需要确保该地址是合法可访问的,否则会导致未定义行为或段错误。 可能需要分步骤说明:首先将地址赋给指针变量,然后通过指针访问内存。例如: int *test_1 = (int*)0x040FA997; int value = test_1[0]; 但实际操作中直接访问特定内存地址可能需要特殊权限,或者在嵌入式系统中才有意义。同时,类型转换必须正确,否则会错误解释内存中的数据。 总结回答的结构应该是: 1. 指针和数组的关系:数组名作为指针指针的下标访问。 2. 如何声明指针变量并赋值地址。 3. 通过指针访问内存的示例代码。 4. 注意事项,如类型匹配、内存合法性。 此外,用户可能混淆了数组和指针的声明,需要指出如果test_1是数组,则无法直接赋值为地址值。而如果是指针,则可以。同时,test_1[0]的有效性取决于test_1是否为指针或数组名。 最后,相关问题的生成需要考虑指针操作的其他方面,如指针算术、数组与指针的区别、内存安全等。</think>在C语言中,通过指针访问内存值需要明确指针类型与内存访问方式的关系。以下是分步说明: --- ### **1. 指针与数组的关系** - **数组名本质**:数组名是首元素地址的常量指针。例如,`int arr[5]`中,`arr`等价于`&arr[0]`,类型为`int*`。 - **指针下标操作**:指针可通过下标访问内存,`p[i]`等价于`*(p + i)`,例如: ```c int *p = arr; p[0] = *(p + 0); // 等同于访问arr[0] ``` --- ### **2. 已知地址访问内存的步骤** 假设`test_1`被定义为指针变量并指向地址`0x040FA997`: ```c // 显式声明指针类型(例如char类型指针) char *test_1 = (char*)0x040FA997; char value = test_1[0]; // 访问地址0x040FA997的第一个字节 ``` - **关键点**: 1. **类型决定解释方式**:指针类型(如`char*`、`int*`)决定如何解释内存值。若为`int*`,则`test_1[0]`会读取4字节(32位系统)[^3]。 2. **地址合法性**:直接访问硬编码地址可能导致段错误(如访问受保护的内存区域)。 --- ### **3. 完整示例代码** ```c #include <stdio.h> int main() { // 将test_1定义为指向特定地址的指针 unsigned int address = 0x040FA997; char *test_1 = (char*)address; // 按字节访问 // 读取test_1[0]的值(第一个字节) printf("Value at 0x%x: %d\n", address, test_1[0]); return 0; } ``` --- ### **4. 注意事项** - **类型匹配**:若目标地址存储的是`int`类型,需使用`int*`指针以避免错误解释内存。 - **内存安全**:直接操作物理地址需在嵌入式系统或内核编程中谨慎使用,应用程序中可能引发崩溃[^2]。 - **数组与指针差异**:数组名是常量指针,不可修改;普通指针变量可重新赋值[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值