首页 > 代码库 > 9.18 内存区域 全局变量 线程 插值查找 位域 栈的实现

9.18 内存区域 全局变量 线程 插值查找 位域 栈的实现

栈区可以修改默认大小配置:
栈区默认的大小是1M,在vs2013中可以修改。



堆区和栈区的地址区别:
栈是连续的,向上增长,地址越来越小。类似数组。
堆是链接的,向下增长,地址越来越大。类似链表。

栈区   高地址到低地址
堆区   低地址到高地址

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main()
  4. {
  5. int a = 1, b = 2;
  6. printf("%p,%p\n", &a, &b); //a的地址大于b的地址
  7. char *p1 = malloc(1);
  8. char *p2 = malloc(1);
  9. printf("%p,%p\n", &p1, &p2);//p1的地址大于p2的地址
  10. printf("%p,%p\n", p1, p2);//p1指向的地址小于p2指向的地址
  11. return 0;
  12. }


代码区:只读不可写

int  a = 45;  //a在栈上        45在寄存器

常量字符串在代码区:
char *p = "calc"; //  p在栈上,  “calc”在代码区
  1. char *p = "liuwei"; //指针只存了地址
  2. printf("%d,%d\n",sizeof(p),sizeof("liuwei")); // 4 7


全局变量的注意事项:

1.    全局变量前一定不能加上 auto   不能放在栈上。

2.    全局变量具有声明和定义的区别。
int a;
int a;
int a;
这种是可以通过编译的。因为三个都属于声明。   int a;这样没有赋值的属于声明。 
不过局部内,这样就不可以了,局部变量没有声明和定义的区别。
  1. #include <stdio.h>
  2. int a;
  3. int a;
  4. int a;
  5. int main()
  6. {
  7. printf("%d\n", a); //结果输出0.
  8. return 0;
  9. }
3.    全局变量如果只有声明,没有定义,会自动初始化0。因为是在Bss段。

4.    全局如果  int a = 1; int a = 2;会出现多重定义问题。有赋值运算符的属于定义。

5.    不同文件的全局变量:

全局变量可以跨文件使用、同一个工程,不同源文件,不能出现两个同名变量的定义 。 

当两个文件同时使用一个全局变量时,需要在另一个文件内,先extern声明,再使用。
见朱老师9.1 作用域 static extern malloc relloc

因此头文件最好只声明,不要定义,免得包含多次,就会出现多定义。当然可以用ifdef避免


函数默认是全局函数:
函数默认都是全局函数,跨文件的函数可以直接使用。
a.c
  1. #include <stdio.h>
  2. int main()
  3. {
  4. gogo();
  5. return 0;
  6. }
b.c
  1. #include <stdio.h>
  2. void gogo()
  3. {
  4. printf("gogo\n");
  5. }
可以直接打印出gogo,虽然在a.c里没有函数声明,因为函数默认就是全局的



但是本文件内部调用函数之前声明,或者在前面定义
  1. #include <stdio.h>
  2. void gogo();//函数声明
  3. int main()
  4. {
  5. gogo();
  6. }
  7. void gogo()
  8. {
  9. printf("gogo\n");
  10. }



线程:                             

#include <process.h> //包含线程头文件

_beginthread();//开启一个线程
  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <process.h>
  4. void runMsg(void *p)
  5. {
  6. MessageBoxA(0, "hello", "world", 0);
  7. }
  8. void main()
  9. {
  10. _beginthread(runMsg, 0, NULL);
  11. _beginthread(runMsg, 0, NULL);
  12. _beginthread(runMsg, 0, NULL);
  13. getchar();//不加getchar()不行,因为主线程结束了,其他线程都挂掉了
  14. }

线程传递参数:
  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <process.h>
  4. void run(void *p)
  5. {
  6. MessageBoxA(0, "hello", p, 0);
  7. }
  8. int main()
  9. {
  10. _beginthread(run, 0, "ABC");
  11. _beginthread(run, 0, "CDE");
  12. _beginthread(run, 0, "XYZ");
  13. getchar();
  14. return 0;
  15. }

如果想传递多个参数,可以传递结构体的指针
  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <process.h>
  4. struct STU
  5. {
  6. char name[10];
  7. char title[10];
  8. };
  9. struct STU stu[3] = { {"hello","world"}, {"fuck","shit"}, {"apple","pear"} };
  10. void run(void *p)
  11. {
  12. struct STU *tmp = (struct STU *)p;
  13. MessageBoxA(0, tmp->name, tmp->title, 0);
  14. }
  15. int main()
  16. {
  17. for (int i = 0; i < 3;i++)
  18. {
  19. _beginthread(run, 0, &stu[i]);
  20. }
  21. getchar();
  22. return 0;
  23. }




位域实战代码:                        

通过位域实现输入一个数,输出其补码
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include <stdio.h>
  3. typedef struct
  4. {
  5. unsigned char ch1 : 1;
  6. unsigned char ch2 : 1;
  7. unsigned char ch3 : 1;
  8. unsigned char ch4 : 1;
  9. unsigned char ch5 : 1;
  10. unsigned char ch6 : 1;
  11. unsigned char ch7 : 1;
  12. unsigned char ch8 : 1;
  13. }bit;
  14. int main()
  15. {
  16. int num;
  17. scanf("%d", &num);
  18. bit *mybit = &num;
  19. for (int i = 3; i >= 0; i--) //地址要从高字节打到低字节
  20. {
  21. printf("%d%d%d%d %d%d%d%d ",
  22. mybit[i].ch8, mybit[i].ch7, mybit[i].ch6, mybit[i].ch5,
  23. mybit[i].ch4, mybit[i].ch3, mybit[i].ch2, mybit[i].ch1);
  24. }
  25. return 0;
  26. }



插值查找(二分查找升级版,注意只能在有序并且分布均匀的情况下查找)
  1. #include <stdio.h>
  2. int find(int *a, int n, int key)
  3. {
  4. int low = 0, high = n - 1;
  5. int mid, count = 0;
  6. while (low <= high)
  7. {
  8. printf("查找第%d次\n", ++count);
  9. //mid = (low + high) / 2; 二分查找bug版本
  10. //mid = low + (high - low) / 2; 二分查找正确版
  11. mid = low + (high - low) * (key - a[low]) / (a[high] - a[low]);//插值查找
  12. if (a[mid] == key)
  13. return mid;
  14. else if (a[mid] < key)
  15. low = mid + 1;
  16. else
  17. high = mid - 1;
  18. }
  19. return -1;
  20. }
  21. int main()
  22. {
  23. int i;
  24. int a[1024 * 100];
  25. for (i = 0; i < 1024 * 100; i++)
  26. a[i] = i;
  27. int pos = find(a, 1024 * 100, 102);
  28. if (pos != -1)
  29. printf("%d %d\n", pos, a[pos]);
  30. else
  31. printf("没有找到\n");
  32. }
注:二分查找的一个bug
见:排序算法

数据结构栈,实现递归:

栈的数据结构实现:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #define N 50
  4. struct stack
  5. {
  6. int top;
  7. int data[N];
  8. };
  9. void init_stack(struct stack *p)
  10. {
  11. p->top = -1;
  12. memset(p->data, 0, sizeof(int)*N);
  13. }
  14. int is_empty(struct stack *p)
  15. {
  16. if (p->top == -1)
  17. return 1;
  18. else
  19. return 0;
  20. }
  21. int is_full(struct stack *p)
  22. {
  23. if (p->top == N - 1)
  24. return 1;
  25. else
  26. return 0;
  27. }
  28. void push_stack(struct stack *p, int key)
  29. {
  30. if (is_full(p))
  31. return;
  32. p->top++;
  33. p->data[p->top] = key;
  34. }
  35. int pop_stack(struct stack *p)
  36. {
  37. if (is_empty(p))
  38. return -1;
  39. int data = p->data[p->top];
  40. p->top--;
  41. return data;
  42. }
  43. int main()
  44. {
  45. struct stack mystack;
  46. init_stack(&mystack);
  47. int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  48. int i;
  49. for (i = 0; i < 10; i++)
  50. {
  51. push_stack(&mystack, a[i]);
  52. }
  53. while (!is_empty(&mystack))
  54. {
  55. printf("%d\n", pop_stack(&mystack));
  56. }
  57. return 0;
  58. }

递归打印一个整数的二进制
  1. #include <stdio.h>
  2. void bin(int num)
  3. {
  4. if (num == 0)
  5. return;
  6. bin(num / 2);
  7. printf("%d\n", num % 2); // 1 0 1 0
  8. }
  9. int main()
  10. {
  11. bin(10);
  12. return 0;
  13. }

用上面的数据结构实现以上的递归。
  1. int main()
  2. {
  3. struct stack mystack;
  4. init_stack(&mystack);
  5. int num = 10;
  6. while (num)
  7. {
  8. push_stack(&mystack, num % 2);
  9. num /= 2;
  10. }
  11. while (!is_empty(&mystack))
  12. {
  13. printf("%d\n", pop_stack(&mystack));
  14. }
  15. return 0;
  16. }




来自为知笔记(Wiz)


9.18 内存区域 全局变量 线程 插值查找 位域 栈的实现