您的位置:首页 > 编程语言 > C语言/C++

【学习ios之路:C语言】存储区内存划分

2014-12-18 21:38 549 查看
一. 内存存储区的划分:
1.栈区:栈区主要存放函数内部定义的变量,数组.函数调用时,开辟空间,函数执行完毕,回收空间,空间的开辟与回收有系统管理.
2.堆区:堆区最大的特点:空间的开辟与释放有开发人员手动管理.
3.全局区静态区:主要存放函数外部定义的全局变量以及静态变量,空间一旦开辟,就不会回收.直到应用程序执行结束.
4.常量区:存储常量.1.整形常量.2.浮点型常量.3,字符串常量.4.字符串常量.
5.代码区:存放程序编译之后生成的cpu指令.

二.malloc,在堆区开辟空间.

//在堆区开辟空间.
//void * 泛型:可以代表所有的指针类型.
//如果要存储两个整数,用int * ,存储8个字符,用char * ,存储4个人整数,用short *.
//malloc 在堆区开辟n个字节大小的空间,返回空间的首地址.
char *p = malloc(8);
//存储iphone
strcpy(p, "iphome");
printf("%s\n",p);//iphome
//释放空间
//删除只是标记删除,不会清楚空间上的内容.
free(p); p = NULL;


三.堆区空间问题.

1.野指针问题:访问没有所有权的空间.
2.过度释放:一块空间释放多次,程序会立即crash.
3.内存泄露:空间没有释放,造成内存堆积.不会造成立即crash,安全隐患.
处理方法 : p = NULL;

使用指针必备条件: 1.指针要由明确的指向.
2.指向一个可以控制的区域

四.malloc应用

1.一个有5个元素的数组空间.存储5个整数.

int  *p = malloc(sizeof(int)*5);
for (int i = 0; i < 5; i++) {
p[i] = arc4random() % (40 - 20 + 1) + 20;
printf("%d ",p[i]);
}
printf("\n");

//排序
for (int i = 0; i < 5 - 1; i++) {
for (int j = 0; j < 5 - 1 - i; j++) {
if (p[j] > p[j + 1]) {
int temp = p[j];
p[j] = p[j + 1];
p[j + 1] = temp;
}
}
}
for (int i = 0; i < 5; i++) {
printf("%d ",p[i]);
}

free(p);
p = NULL;


2.有一个字符串,其中包含数字,提取其中的数字,要求动态分配内存保存.

printf("请输入一段字符串:\n");
char str[] = {0};
scanf("%s",str);
int i = 0;
int num = 0;
while (str[i] != '\0') {
if (str[i] >= '0' && str[i] <= '9') {
num++;
}
i++;
}
char *q = malloc(sizeof(char)*(num+1));//根据长度生成空间 num + 1 字符串隐藏\0
int m = 0,n = 0;
for (int i = 0; i < num; i++) {
while (str[m] != '\0') {
if (str[m] >= '0' && str[m] <= '9') {
q
= str[m];
n++;
}
m++;
}
}
q
= '\0';//多出来的存储\0
printf("\n");
for (int i = 0; i < num; i++) {
printf("%c", q[i] );
}
free(q);
q = NULL;


3.输入3个学员的姓名,动态分配内存保存学员姓名,并在最后输出.

char *names[3] = {0}; //存储在堆区开辟的空间的首地址.
char temp[255] = {0};//存储从控制台输入的字符串
for (int i = 0; i < 3; i++) {
printf("请输入3个学生的姓名");
scanf("%s", temp);//输入到temp临时数组中.
//动态计算输入的字符串的长度
unsigned long length = strlen(temp);
//在堆区开辟空间.
names[i] = malloc(length + 1);//将堆区空间的地址存储指针数组中,
//将内容拷贝到堆区.
strcpy(names[i], temp);

}

for (int i = 0; i < 3; i++) {
printf("%s \n",names[i]);
free(names[i]);<span style="font-family: Arial, Helvetica, sans-serif;">//空间的释放</span>
names[i] = NULL;

}


(2)calloc用法

1.void * calloc(unsigned n, unsigned size);
分配n个size大小的空间.并且把该内存上的所有字节清零.
int *p = calloc(5, 4);//分配5块大小为4字节的空间,并且做清零操作.

free(p);
p = NULL;
(3)realloc 用法

void *realloc(void *p,unsigned newSize);
int *p = malloc(10);
printf("%p\n",p);
int *q = realloc(p, 40);//重新分配一个大小为100 的空间.
//realloc 返回当前空间的首地址.如果当前空间不够,则在另一块申请20个字节的空间,此时返回新的空间的地址.
printf("%p\n",q);
free(q);
q = NULL;
p = NULL;//不需要释放.


(4)memcpy用法

void *memcpy (void *dest, const void *source, size_t n);
//从source指向内存开始拷贝到dest中n个字节.

char *p1 = malloc(8);
char *p2 = malloc(8);

strcpy(p2, "frank");
printf("%s\n", p2);
//memcpy(p1, p2, 6);

memcpy(p1, p2, 4);
memcpy(p1, p2 + 2, 4);//ank
p1[4] = '\0';
printf("%s\n", p1);//fran
(5)memset用法

<pre name="code" class="cpp">4. void * memset(void *s, int c, size_t n);
//从s指向的内存开始初始化n个字节的内容为c
char *p1 = malloc(8);
memset(p1,0,8);




五.练习
定义两个整型指针,分别用malloc、calloc对其分配空间保存3个元素,malloc分配的空间用memset清零,随机对数组进行赋值随机范围1-3,赋值后用memcmp比较两个数组。如果相同打印Good!否则打印Failed..

int *p = malloc(sizeof(int) * 3);
int *q = calloc(3, sizeof(int));
memset(p, 0, sizeof(int) * 3);
for (int i = 0;i < 3;i++) {
p[i] = arc4random() % (3 - 1 + 1) + 1;
q[i] = arc4random() % (3 - 1 + 1) + 1;
printf("p:%d q:%d\n",p[i],q[i]);
}

//比较buf1和buf2指向的内存是否相同,比较count个字节
if(memcmp(p , q , sizeof(int) * 3) == 0){ //地址 .3即3个字节.
printf("profect\n");
} else {
printf("failed\n");
}

free(p);
free(q);
p = NULL;
q = NULL;


六.宏

定义宏:
三部分:1.#define 2.宏名 3. 替换的内容
宏的作用:
只做替换.
宏名的命名规范: 1.全部大写 2. k+驼峰
无参宏 #define kArrayNumber5 #define N
10
有参宏 #define MUL(A,B) ((A) * (B))
宏应该注意的几个问题.
1.宏名大写
2.参数一定要加小括号.
3.宏替换的内容不要加分号.
4.对于有参宏,宏名一与参数之间不要加空格.

七.枚举
定义枚举
枚举的作用 :罗列出所有的可能性
枚举是将人能够识别的标示符和计算机能够识别的数字结合在一起.
例子:

//定义枚举
typedef enum button {
//通过1的每一位来表示一个状态.
Close = 1 << 0,//关闭 001    第一位1表示关闭
Max = 1 << 1, // 最大化 010   第二位为1表示最大化
Min = 1 << 2//最小化 100      第三位为1表示最小化

}Button;
如果想宝贝多个枚举值,按位或即可,前提是枚举值通过左移符号对应值.
BOOL b = Close | Max | Min; //001 010 100 = 111
printf("%d\n", b);


八.条件编译

以#开头的叫做预编译指令
预编译指令做一些文本以及代码的替换工作.
形式1:

#define A
#ifdef A
int a = 10;//条件编译(根据条件编译不同的代码)
#else
int a = 20;
#endif
printf("%d ", a);//10
形式2:

#define A
#ifndef A //如果没有定义
int a = 10;//条件编译(根据条件编译不同的代码)
#else
int a = 20;
#endif
printf("%d\n",a);//20


形式3:

# if  10 //非0即为真,执行if,否则为假,执行else
int a = 10;
#else
int b = 20;
#endif
printf("%d\n", a); //10
九.面试题 #include 与 #import
的区别

#import 相比 #include 能够防止重复导入,引起交叉编译.
#import " " 导入自定义的头文件
#impoer <> 导入系统的头文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: