新闻中心

EEPW首页>嵌入式系统>设计应用> C语言程序内存分配

C语言程序内存分配

作者: 时间:2016-11-27 来源:网络 收藏

(1) & 与 * 操作

取地址运算符 &: p = &c;

--表达式解析: 将 c 的地址赋值给 变量 p, p 是指向 c 变量的指针;

--& 可以使用的情况: 取地址操作 只能用于内存中的对象, 如变量 或 数组, 栈内存 堆内存 都可以;

--& 不适用的情况: 不能用于 表达式, 常量, register类型变量;

间接引用运算符: * ;

--声明指针: int *p ; 该表达式的含义是*p 的结果是 int 类型, 声明变量 a, int a, 声明指针 *p , int *p;

--获取指针指向的值: int a = *p ;

(2) 指针定义解析

声明指针 和 函数: int *p, max(int a, int b), 声明指针变量 语法 与声明 变量语法类似, 同理声明函数也一样;

--原理: *p 和 max()返回值 类型都是 int 类型;

指针指向: 每个指针都必须指向某种特定类型;

--例外: void *p 可以指向任何类型, 但是 p 不能进行取值运算, *p 是错误的, 因为不知道 p 指向的数据类型;

(3) 指针运算及示例

指针相关运算: int x = 0; int *p = &x; 那么*p 就可以代表x;

--算数运算: x = x + 1; 等价于 *p = *p + 1 ; int y = x + 1; 等价于 int y = *p + 1;

--自增运算: 前提 : ++, * 运算顺序是自右向左; ++*p 和 (*p)++, p 指向的值自增1, 注意要加上括号, 否则会将地址自增;

--指针赋值: int *p, *q; int a = 0; p = &a; q = p; 最终结果 p 和 q 都指向了 变量 a;

示例程序:

[cpp]view plaincopy
  1. /*************************************************************************
  2. >FileName:pointer_address.c
  3. >Author:octopus
  4. >Mail:octopus_work.163.com
  5. >CreatedTime:Mon10Mar201409:52:01PMCST
  6. ************************************************************************/
  7. #include
  8. intmain(intargc,char**argv)
  9. {
  10. int*p,*q;
  11. inta=10,b;
  12. //p指针指向a变量
  13. p=&a;
  14. //*p可以代替a进行运算
  15. ++*p;
  16. b=*p+5;
  17. //指针之间可以直接相互赋值
  18. q=p;
  19. //打印p和q指针指向的值
  20. printf("*p=%d",*p);
  21. printf("*q=%d",*q);
  22. return0;
  23. }


执行结果:

[cpp]view plaincopy
  1. [root@ip28pointer]#gccpointer_address.c
  2. [root@ip28pointer]#./a.out
  3. *p=11
  4. *q=11

4. 函数参数的传值调用和传址调用

(1) 传值调用 和 传址调用

传值调用: 以传值的方式将参数传递给函数, 不能直接修改主函数中变量的值, 仅仅是将副本传递给了函数;

传址调用: 将 变量的指针 传递给函数, 当函数对指针进行操作的时候, 主函数中的值也进行了对应变化;

交换函数示例1:

[cpp]view plaincopy
  1. /*************************************************************************
  2. >FileName:swap.c
  3. >Author:octopus
  4. >Mail:octopus_work.163.com
  5. >CreatedTime:Mon10Mar201411:07:18PMCST
  6. ************************************************************************/
  7. #include
  8. voidswap_1(inta,intb)
  9. {
  10. inttemp;
  11. temp=a;
  12. a=b;
  13. b=temp;
  14. printf("swap_1传值函数a=%d,b=%d",a,b);
  15. }
  16. voidswap_2(int*a,int*b)
  17. {
  18. inttemp;
  19. temp=*a;
  20. *a=*b;
  21. *b=temp;
  22. printf("swap_2传址函数a=%d,b=%d",*a,*b);
  23. }
  24. intmain(intargc,char**argv)
  25. {
  26. inta=10,b=5;
  27. printf("初始值:a=%d,b=%d",a,b);
  28. swap_1(a,b);
  29. printf("执行swap_1函数,a=%d,b=%d",a,b);
  30. swap_2(&a,&b);
  31. printf("执行swap_2函数,a=%d,b=%d",a,b);
  32. return0;
  33. }


执行结果:

[cpp]view plaincopy
  1. [root@ip28pointer]#gccswap.c
  2. [root@ip28pointer]#./a.out
  3. 初始值:a=10,b=5
  4. swap_1传值函数a=5,b=10
  5. 执行swap_1函数,a=10,b=5
  6. swap_2传址函数a=5,b=10
  7. 执行swap_2函数,a=5,b=10



示例解析:

--传值调用: swap_1 是传值调用, 传入的是 main 函数中的 a b 两个变量的副本, 因此函数执行完毕后, 主函数中的值是不变的;

--传址调用: swap_2 是传址调用, 传入的是 a , b 两个变量的地址 &a, &b, 当在swap_2 中进行修改的时候, 主函数中的 a,b变量也会发生改变;

(2) 高级示例

需求分析: 调用getint()函数, 将输入的数字字符 转为一个整形数据;

getch 和 ungetch 函数:

--使用场景: 当进行输入的时候, 不能确定是否已经输入足够的字符, 需要读取下一个字符, 进行判断, 如果多读取了一个字符, 就需要将这个字符退回去;

--使用效果: getch() 和 ungetch() 分别是预读下一个字符, 和 将预读的字符退回去, 这样对于其它代码而言, 没有任何影响;

注意的问题 : 出现问题, 暂时编译不通过, 找个C语言大神解决;

代码:

[cpp]view plaincopy
  1. /*************************************************************************
  2. >FileName:getint.c
  3. >Author:octopus
  4. >Mail:octopus_work.163.com
  5. >CreatedTime:Mon10Mar201411:40:19PMCST
  6. ************************************************************************/
  7. #include
  8. #include
  9. #include
  10. #defineSIZE5
  11. intgetint(int*p)
  12. {
  13. //sign是用来控制数字的正负
  14. intc,sign;
  15. //跳过空白字符,如果是空白字符,就会进行下一次循环,直到不是空白字符为止
  16. while(isspace(c=getc(stdin)));
  17. //如果输入的字符不是数字,就将预读的数据退回到标准输入流中
  18. if(!isdigit(c)&&c!=EOF&&c!=+&&c!=-)
  19. {
  20. ungetc(c,stdin);
  21. return0;
  22. }
  23. /*
  24. *如果预读的是减号,那么sign标识就是-1,
  25. *如果预读的是加号,那么sign标识就是1;
  26. */
  27. sign=(c==-)?-1:1;
  28. //如果c是加号或者减号,再预读一个字符&
  29. if(c==+||c==-)
  30. c=getc(stdin);
  31. for(*p=0;isdigit(c);c=getc(stdin))
  32. *p=10**p+(c-0);
  33. *p*=sign;
  34. if(c!=EOF)
  35. ungetc(c,stdin);
  36. returnc;
  37. }
  38. intmain(intargc,char**argv)
  39. {
  40. intn,array[SIZE],i;
  41. for(n=0;n
  42. for(i=0;i
  43. {
  44. printf("array[%d]=%d",i,array[i]);
  45. }
  46. return0;
  47. }

执行结果:

[plain]view plaincopy
  1. octopus@octopus-Vostro-270s:~/code/c/pointer$./a.out
  2. 123
  3. 12343
  4. 6741
  5. array[0]=123
  6. array[1]=123
  7. array[2]=43
  8. array[3]=674
  9. array[4]=1

5. 指针 和 数组

指针数组比较:

--可互相替代: 数组下标执行的操作都可以使用指针替代;

--效率比较: 使用指针操作效率比数组要高;

指针 与 数组初始化:

--声明数组: int a[10]; 定义一个长度为10 的int数组;

--声明指针: int *p; 定义一个指针, 该指针指向整型;

--相互赋值: p = &a[0], 将数组第一个元素的地址赋值给指针变量;

--使用指针获取数组对象: *p 等价于 a[0], *(p + 1) 等价于 a[1], *(p + i)等价于 a[i];

--注意地址的运算: p + i , 在地址运算上, 每次增加 sizeof(int) * i 个字节;

将数组赋值给指针的途径:

--将数组第一个元素地址赋值给指针变量: p = &a[0];

--将数组地址赋值给指针变量: p = a;

指针 和 数组 访问方式互换: 前提 int *p, a[10]; p = a;

--数组计算方式: 计算a[i]的时候, 先将数组转化为 *(a + i)指针, 然后计算该指针值;

--取值等价: a[i] 等价于 *(p + i);

--地址等价: &a[i] 与 a + i 是等价的;

--指针下标访问: p[i] 等价于 *(p + i);

--结论: 通过数组和下标实现的操作 都可以使用指针和偏移量进行等价替换;

指针 和 数组 的不同点:

--指针是变量: int *p, a[10]; p = a 和 p++ 没有错误;

--数组名不是变量: int *p, a[10]; a = p 和 a++ 会报错;

数组参数:

--形参指针: 将数组传作为参数传递给函数的时候, 传递的是数组的首地址, 传递地址, 形参是指针;

数组参数示例:

--函数参数是数组: 函数传入一个字符串数组参数, 返回这个字符串长度;

[cpp]view plaincopy
  1. /*************************************************************************
  2. >FileName:array_param.c
  3. >Author:octopus
  4. >Mail:octopus_work.163.com
  5. >CreatedTime:Sat15Mar201412:46:57AMCST
  6. ************************************************************************/
  7. #include
  8. //计算字符串长度
  9. intstrlen(char*s)
  10. {
  11. intn;
  12. for(n=0;*s!=;s++)
  13. n++;
  14. returnn;
  15. }
  16. intmain(intargc,char**argv)
  17. {
  18. printf("strlen(djdhaj)=%d",strlen("djdhaj"));
  19. printf("strlen(12)=%d",strlen("12"));
  20. printf("strlen(dfe)=%d",strlen("dfe"));
  21. }


--执行结果:warning: conflicting types for built-in function ‘strlen’, 原因是 C语言中已经有了 strlen 函数了, 如果改一个函数名, 就不会有这个警告了;

[plain]view plaincopy
  1. [root@ip28pointer]#gccarray_param.c
  2. array_param.c:12:warning:conflictingtypesforbuilt-infunction‘strlen’
  3. [root@ip28pointer]#./a.out
  4. strlen(djdhaj)=6
  5. strlen(12)=2
  6. strlen(dfe)=3



数组和指针参数:将数组名传给参数, 函数根据情况判断是作为数组还是作为指针;

--实参: 指针偏移量 和 数组下标 都可以作为 数组或指针函数形参, 如 数组情况fun(&array[2]) 或者 指针情况fun(p + 2);

--形参: 函数的形参可以声明为 fun(int array[]), 或者 fun(int *array), 如果传入的是数组的第二个元素的地址, 可以使用array[-2]来获数组取第一个元素;

数组指针参数示例:

[cpp]view plaincopy
  1. /*************************************************************************
  2. >FileName:param_array_pointer.c
  3. >Author:octopus
  4. >Mail:octopus_work.163.com
  5. >CreatedTime:Sat15Mar201401:28:33AMCST
  6. ************************************************************************/
  7. #include
  8. //使用指针做形参取指针的前两位和当前位
  9. voidfun_p(int*p)
  10. {
  11. printf("*(p-2)=%d",*(p-2));
  12. printf("*p=%d",*p);
  13. }
  14. //使用数组做形参取数组的第-2个元素和第0个元素
  15. voidfun_a(intp[])
  16. {
  17. printf("p[-2]=%d",p[-2]);
  18. printf("p[0]=%d",p[0]);
  19. }
  20. intmain(intargc,char**argv)
  21. {
  22. intarray[]={1,2,3,4,5};
  23. //向指针参数函数中传入指针
  24. printf("fun_p(array+2):");
  25. fun_p(array+2);
  26. //向数组参数函数中传入数组元素地址
  27. printf("fun_a(&array[2]):");
  28. fun_a(&array[2]);
  29. //向指针参数函数中传入数组元素地址
  30. printf("fun_p(&array[2]):");
  31. fun_p(&array[2]);
  32. //向数组参数函数中传入指针
  33. printf("fun_a(array+2):");
  34. fun_a(array+2);
  35. return0;
  36. }


执行效果:

[plain]view plaincopy
  1. [root@ip28pointer]#gccparam_array_pointer.c
  2. [root@ip28pointer]#./a.out
  3. fun_p(array+2):
  4. *(p-2)=1
  5. *p=3
  6. fun_a(&array[2]):
  7. p[-2]=1
  8. p[0]=3
  9. fun_p(&array[2]):
  10. *(p-2)=1
  11. *p=3
  12. fun_a(array+2):
  13. p[-2]=1
  14. p[0]=3


http://blog.csdn.net/shulianghan/article/details/20472269


上一页 1 2 下一页

评论


技术专区

关闭