1. 复习RAM
text 部分存储编译后的二进制文件,如源代码。initialized data 和 uninitialized data 分别存储初始化和未初始化的全局变量; heap 负责动态内存分配的内存(如 malloc()函数) 自上而下增长; stack负责存储函数调用,包括局部变量,参数,函数地址以便函数调用结束后还能回到原来调用它的函数继续运行,自下而上增长。
2. 指针
void swap(int a, int b)
{
int temp = a;
a = b;
b = temp;
printf("a=%i\n", a);
printf("b=%i\n", b);
}
以上这个swap函数不能起到交换变量的作用。原因:https://blog.csdn.net/shaozhenghan/article/details/81256477
使用指针即可:
void
swap(int * a, int * b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
传指针形参。
swap函数执行完后,它对应的stack 被 “清除”,即计算机忘记了stack局部变量和参数的存在。但它们确实依然存在。
指针存储一个变量的地址,指针本身所占内存总是一样大,32位或者64位,不管它指向什么类型,char 或者 int
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
char * s1 = argv[1];
printf("%s\n", s1);
char * s2;
s2 = s1;
// *s2 = "mmm";
s2[0] = 'm';
printf("%s\n", s1);
printf("%s\n", s2);
return 0;
}
这段代码,s2 = s1 并不是拷贝!而是因为s1 是指针,指向argv[1]这个字符串的首元素,即char类型。s2 = s1 是将s1存储的地址复制给了s2, 所以s2 也指向 argv[1]的首元素。所以更改s2[0]也同样会对s1[0]改变。
例如:
注意:下面这样的赋值是错的。因为*s2 的类型是整型,而“mmm”是一个指针!
会报错:
warning: assignment makes integer from pointer without a cast [-Wint-conversion]
*s2 = "mmm";
因为s1 未知大小,所以要拷贝,应该用动态内存分配:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char **argv)
{
char * s1 = argv[1];
printf("%s\n", s1);
printf("%i\n", (int)strlen(s1));
char * s2 = malloc((strlen(s1)+1) * sizeof(char));
printf("%i\n", (int)strlen(s2));
unsigned int n = (int)strlen(s1)+1;
for(unsigned int i = 0; i < n; ++i)
{
s2[i] = s1[i];
}
s2[n] = '\0';
s2[0] = 'x';
printf("%s\n", s1);
printf("%s\n", s2);
return 0;
}
其中下面这句很关键。如果没有给s2 分配内存,就试图访问s2,会有segmentation error!
若没有给s2 分配内存,s2 默认为 NULL 也就是 0, 0x00
char * s2 = malloc((strlen(s1)+1) * sizeof(char));
malloc()函数在RAM 的堆heap里面,分配一块指定大小的内存,返回值是这个内存的首地址!
返回的首地址存在s2里面,而s2 则是位于RAM的stack里面!
strlen(s1)+ 1 是因为s2要以‘\0’结束。
乘以sizeof(char)是方便跨平台,因为不同硬件平台上char的大小可能不一样。
运行结果:
可以看到这次是拷贝了。
再一个例子:
int * x;
int * y;
printf("%i\n", *x); // 错误!
int * x = malloc(sizeof(int));
*x = 22; // 正确!指针x已经分配内存了。
*y = 13; // 错误!segmentation error,因为指针y还没有分配内存
y = x;
*y = 13; // 正确。