从*p++说指针,数组,结构和函数
来源:互联网 发布:mac mini 恢复出厂设置 编辑:程序博客网 时间:2024/06/06 03:18
说明文中*p++和*s++都是一个东西,不做字面上的统一了。
因为右结合性,*p++ 其实就是 *(p++)
1.strlen的实现
#include <stdio.h>main(){char str[]= "Abcde";printf("\n string = %s length = %d \n",str,str_length(str));}int str_length (const char *s){int length = 0;while (*s++){length++;}return (length);}其实*s++的过程
递增到最后一位就是\0,也就是“”.
注意:*s已经指向后面的内容了,就是乱码了
2.数组和指针这2种方式表示字符串的差异
#include <stdio.h>main( ){char str[]= "Abcde";char* ptr = "12345";*ptr++;printf ("\n string = %s length = %d \n",ptr,str_length (ptr));printf ("\n string = %s length = %d \n",str,str_length (str));}int str_length (const char *s){int length = 0;while (*s++){length++ ;}return (length) ;}输出:
2.1 数组不能直接当指针用,数组名不能指针运算
也就是说数组名代表数组的首元素,它是一个指针常量,它的值在程序运行期间是固定不变的, *str++是不可以的;
ptr是指针变量当然可以实现ptr++的运算但是指针自然可以指针运算。
直接数组名++就报错了:
2.2 数组名不能直接赋值,但是指针可以
给数组名赋值就报错了:
第1次指针地址是:0x010f5860
第2次指针地址是:0x010f5861
第3次指针地址是:0x010f5868
第4次指针地址还是:0x010f5868
下面是《明解C语言》书的截图:
3. int下*s++,(*s)++,++*s,++(*s)的差异
首先 如果*s是指针,那么*s++就不是将*s的值加1,而是将*s指向的地址加同一个单位大小。所以为了避免类似问题,需要的时候要加括号。
--出自《C语言入门经典 第4版》
#include <stdio.h>void add(int *s){*s++;}int str_length (char *s){int length = 0;while (*s++){length++ ;}return (length) ;}main( ){int a=1;int *b=&a;char str[]= "Abcde";char* ptr = "12345";*ptr++;ptr="def";add(b);printf ("\n string = %s length = %d \n",ptr,str_length (ptr));printf ("\n string = %s length = %d \n",str,str_length (str));}
第1次*s++之前的地址是:0x002afc98
第2次*s++之前的地址是:0x002afc9c
fc9c-fc98=4 就是一个int的大小
*s++只是对s的地址递增然后解引用,得到-858993460,并没有改变*s的值!
跳出函数a没有变化
所以要想得到Int型值的递增可以这样写即可:
void add(int *s){(*s)++;}
由于char*大小正好是1个字节,所以char*的++正好指向下一个字符!
所以在字符串的操作中正好可以用*s++,如果使用了括号,(*s)++这样的话反而会引起内存错误。
4.字符串复制
#include <stdio.h>void xstrcpy ( char *t, char *s ){while ( *s != '\0' ){*t = *s ;s++ ;t++ ;}*t = '\0' ;}void strcpy(char *s,char *t){//while((*s++=*t++)!='\0')//表达式通'\0'的比较是多余的,因为只需要判断表达式的值是否为0即可。while(*s++=*t++);}//标准库实现char * strcpy2(char *s,char *t){char *r=s;while(*s++=*t++);return r;}void main(){char source[] = "Abcde" ;char target[20] ;strcpy ( target, source ) ;printf ( "\nsource string = %s", source ) ;printf ( "\ntarget string = %s", target ) ;}/*想经过函数调用改变某个变量的值,就要传入变量的地址。 如果变量是基本类型,要传入对应的指针类型。 如果变量是指针,要传入指针的指针。 */
--出自《C语言程序设计语言 第2版》
5.说清楚函数传递参数
一开始我们会想既然已经在函数中*s++了,而且也确实改变了指针的位置,但是为什么一回到调用函数中,*s就又复原了?
不是说传指针是按引用传递的么?
其实,误区也正在于此,函数还是传值的,传递的都是原值的拷贝,如果传递指针,在调用函数中使用*解引用,可以改变指针指向的值,但是不能改变指针的内容,因为函数调用只是传递了原始指针指向值地址的拷贝,就是说原始地址拷贝了2份,所以在函数中改变是改变了地址,但是没有意义。
int a = 0x55aa;
change_value(&a, 0xaa55);
这样a的值改变了,真正的情况是参数传递后,编译器做了一个参数拷贝过程,比如声明一个整型指针pCopy = &a;
这样,pCopy只是传进来参数&a的一份拷贝,但是他们都指向了a的地址,因此用这种方法可以改变a 的值。
那么现在有个问题,通过传递一个指针,可以改变该指针所指向地址的内容,那么如何改变指针本身呢?
该怎么做才能改变ptr呢?
既然ptr也是一个变量,我要在函数内部改变它,那么就传递一个指向ptr的指针!也就是二级指针!
6.函数返回指针
绝不返回函数中本地变量的地址。
函数返回指针可以用如下方法:
1.可以用malloc分配内存,并返回这个内存的地址
2.返回指针参数
注意函数中可以声明一个新的结构struct,然后返回结构,但是不可以返回临时指针。
7.数组和指针的差异
数组不是指针,作为参数传递的数组会退化为指针。
为什么C语言把数组形参当做指针?
再来看看《你必须知道的495个C语言问题》
8.数组不能被赋值
数组不能赋值,可以指定数组下标赋值,可以在函数中可以给数组赋值,因为这个时候数组退化为指针。
9.数组的大小
10.指针和结构
结构体指针4个字节,结构体大小要看数据对齐。
分配12个字节,结构吃掉8个,当 (结构地址+1)所以只能第一个元素可以分配到初始化的0,第二个元素就分到垃圾地址了
struct tt{int size;int slabs;};void main(){void *s=malloc(12);struct tt *t1;memset(s,0,12);t1=(struct tt*)s;t1->size=1;t1->slabs=2;}
指针不对齐8a88 和8a90差2 8a90和8a98差8 结构有2个Int 所以结构大小是8
结构和指针的关系
对同一个地址可以转换为任意结构体,虽然数据结构乱了,但是毕竟也是有数据。
所以使用法则也就是使用前先寻址,再强制转换
11.变量作用域
局部变量的作用域一般认为是在函数体内。但是根据C99标准,该说法有了变化。在新的标准中,允许即时定义局部变量,示例如下:
for( int i = 0; i < MAXSIZE; i++ )
{
….
}
例子中的局部变量i的作用域即在for循环的花括号中,当for循环结束的时候,局部变量i的生存周期同时结束。也就是说,在下一个for循环中,你仍然可以再次重新定义并使用名为i的局部变量。该语法只能在C99之后的新的C编译器中使用, 例如VC2005、VC2008、gcc4.2及以上版本。但是,该语法带来了编程风格的变化,而且变量隐含在了执行程序中,无论是代码的阅读和维护都有较大的困难,因此工程项目中不建议使用该语法。
for循环中定义的pit 在离开循环以后就不存在了。
12.传递结构和数组给函数的差异
为什么传递给函数的结构没有像数组一样退化为指针,因为数组可以用指针去偏移量,但是结构无法做到这一点,或者说非常困难。
其实函数参数默认是通过r0,r1,r2,r3四个寄存器传递的,多余的参数是通过将参数压入栈中传递的。同理对于一个结构体如果其大小少于32字节(4个寄存器),按照正常的方式通过r0到r3传递,多于32字节则是将多余的部分在堆栈上建立个备份进行传递。
所以对于在ADS编译器下对于函数参数是结构体的传递,还是传入指针比较好。既高效(省去建立备份的时间),又节省栈空间。
13.指针大小
32位是4个字节,32=4*8
64位是8个字节,64=8*8
在64位的linux下:
而visual studio里默认是win32平台,指针是4个字节大小:
需要修改为x64平台
这时候显示指针是8个字节:
14.指向数组的指针
slabclass_t *p = &slabclass[id];
- 从*p++说指针,数组,结构和函数
- 从main函数学指针数组和指针的指针
- 理解数组,结构 ,函数指针,指针函数,数组指针,指针数组,结构指针的定义和实现
- 指针,数组和结构
- 结构指针和数组
- 关于指针char *p和数组char p[] 的区别
- 指针 *p++和*++p
- 函数指针,指针数组和数组指针
- 数组指针,指针数组和函数指针
- 函数指针和指针函数 数组指针和指针数组
- 数组指针和指针数组,函数指针和指针函数
- 指针函数和函数指针、指针数组和数组指针
- 指针函数和函数指针、指针数组和数组指针
- 数组指针和指针数组 指针函数和函数指针
- 数组指针和函数指针
- 函数指针 和 函数指针数组 和 函数指针数组
- 指针、数组和函数
- 指针.数组和函数
- opencv学习_15 (利用cmake查看opencv的源码)
- arm的2级页表在Linux内核创建过程解析
- 使用MFC中的AfxBeginThread创建多线程
- VS2010 IntelliSense: "不可用于 C++/CLI"
- 成功解决Win7 64位系统下GraphEdit 不能显示Directshow.net远程图表的问题
- 从*p++说指针,数组,结构和函数
- 求组合数
- ORA-38301:can not perform DDL/DML over objects in Recycle Bin
- sqlserver常用函数笔记。。。
- UITableViewCell 单组数据展示——实现游戏英雄单组展示
- Android(Java):用户体验性 易用性 意 宜 益 怡
- Java格式化输出 Dom4j转义字符问题
- maven环境快速搭建
- 十八大三中全会召开,给政府互联网发展带来了新的春天