深入理解c语言指针与内存
一、将int强制转换为int指针,将int指针强转换为int
void f(void)
{
int *p = (int*)100; //将int强制转换为int指针
printf("%d\n",(int)p+1); //将int指针强转换为int, 然后+1
printf("%d\n",(int)(p+1)); //将int指针加1(地址增加了4),强制转换为int
}
int main(int ac, char **av)
{
f();
return 0;
}
运行结果:
101
104
二、int指针转换为char指针
#include <stdio.h>
int main() {
int a = 8;
int* b = &a;
int *c = (int*)((char*)b + 1);
printf("b = %p, c = %p\n", b, c);
*c = 8;
printf("%d\n", a);
printf("b = %p, c = %p\n", b, c);
printf("%d\n", *c);
return 0;
}
运行结果:
b = 0061FEC4, c = 0061FEC5
2056
b = 0061FEC4, c = 0061FE00
1988445728
运行完第7行:整数a的地址为b = 0x61fec4,内存值为08000000;指针c指向0x61fec5,是a的第二个字节的地址。(小端存储)
运行完第8行,对c指向的内存赋值,这个四个字节被写为 08000000,因此a指向的内存被写为:00000808(b) = 2056(d)。
但由于存储c这个指针的内存正好因此被破坏了,被修改为0061FE00,因此此次输出*c的内容是未知的。
三、数组&指针
1. S6.828
#include <stdio.h>
#include <stdlib.h>
void f(void)
{
int a[4];
int *b = malloc(16);
int *c;
int i;
printf("1: a = %p, b = %p, c = %p\n", a, b, c);
c = a;
for (i = 0; i < 4; i++)
a[i] = 100 + i;
c[0] = 200;
printf("2: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c[1] = 300;
*(c + 2) = 301;
3[c] = 302; // 由于arr[2]等价于*(arr+2), 因而对于2[arr], 其实也就等价于*(2+arr)也是可以通过编译的, 因为+是满足交换律的。
printf("3: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c = c + 1;
*c = 400;
printf("4: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
c = (int *) ((char *) c + 1);
*c = 500;
printf("5: a[0] = %d, a[1] = %d, a[2] = %d, a[3] = %d\n",
a[0], a[1], a[2], a[3]);
b = (int *) a + 1;
c = (int *) ((char *) a + 1);
printf("6: a = %p, b = %p, c = %p\n", a, b, c);
}
int main(int ac, char **av)
{
f();
return 0;
}
运行结果:
1: a = 0061FEA0, b = 007515B8, c = 0000003D
2: a[0] = 200, a[1] = 101, a[2] = 102, a[3] = 103
3: a[0] = 200, a[1] = 300, a[2] = 301, a[3] = 302
4: a[0] = 200, a[1] = 400, a[2] = 301, a[3] = 302
5: a[0] = 200, a[1] = 128144, a[2] = 256, a[3] = 302
6: a = 0061FEA0, b = 0061FEA4, c = 0061FEA1
Process finished with exit code 0
2. 在 C/C++中,数组和指针是相互关联又有区别的两个概念。
-
当我们声明一个数组时,其数组的名字也是一个指针,该指针指向数组的第一个元素。我们可以用一个指针来访问数组。data1是一个数组,sizeof(data1)是求数组的大小。
-
data2声明为指针,尽管它指向了数组data1的第一个数字,但它的本质仍然是一个指针。
-
在C/C++中,当数组作为函数的参数进行传递时,数组就自动退化为同类型的指针。
#include <stdio.h>
#include <stdlib.h>
int GetSize(int data[]){
return sizeof(data);
}
int main(void) {
int data1[] = {1,2,3,4,5};
int size1 = sizeof(data1);
int* data2 = data1;
int size2 = sizeof(data2);
int size3 = GetSize(data1);
printf("%d %d %d %d\n", size1, size2, size3);
return 0;
}
输出:
64位操作系统
20 8 8 8
四、函数返回局部指针?
- 以下代码IDE会告警:
Address of stack memory associated with local variable 't' returned
。由于局部变量的指针分配在栈上,且函数执行完,栈内存会自动释放,因此reverseLeftWords
的返回值总是为NULL,不能得到正确的结果。
char* reverseLeftWords(char* s, int n){
size_t sSize = strlen(s);
if( n == 0 || n >= sSize) return s;
char t[sSize+1];
size_t i;
for(i = 0; i < sSize; i++){
t[i] = s[(i + n)% sSize];
}
t[i] = '\0';
return t;
}
- 需要通过malloc来分配堆上内存,返回堆内存地址。
char* reverseLeftWords(char* s, int n){
size_t sSize = strlen(s);
if( n == 0 || n >= sSize) return s;
char* t = (char*)malloc(sizeof(char*)*(sSize+1));
size_t i;
for(i = 0; i < sSize; i++){
t[i] = s[(i + n)% sSize];
}
t[i] = '\0';
return t;
}