学习笔记02
来源:互联网 发布:乐知英语待遇 编辑:程序博客网 时间:2024/03/29 07:09
----------20150913----------------
1. 函数参数 a[]和*a为啥是一样的?
即fun(char a[])和fun(char *a)是一样的
找了一个比较好的分析:
最近的项目中有不少c的程序,在与项目新成员的交流中发现,普遍对于char *s1 和 char s2[] 认识有误区(认为无区别),导致有时出现“难以理解”的错误。一时也不能说得很明白,网上也搜了一下相关文章发现一些写的比较好的,综合了一下当教育资料备用。
char *s1 = "hello";
char s2[] = "hello";
【区别所在】
char *s1 的s1,指针是指向一块内存区域,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。
char s2[]的s2 是数组对应着一块内存区域,其地址和容量(数组大小)在生命期里不会改变,只有数组的内容可以改变
【内存模型】
+-----+ +---+---+---+---+---+---+
s1: | *======> | h | e | l | l | o |\0 |
+-----+ +---+---+---+---+---+---+
+---+---+---+---+---+---+
s2: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+
场景一)
char *s1 = "hello";
char s2[] = "hello";
s2=s1; //编译ERROR
s1=s2; //OK
分析:s2其地址和容量在生命期里不能改变
场景二)
char s2[] = "hello";
char *s1 = s2; //编译器做了隐式的转换 实际为&s2
或
char *s1 = &s2;
分析:以上两个指针复值完全等价,由于编译器会做这个隐式转换也容易导致初学者误认为 char *s 与char s[]是一回事。
另用第二种在一些编译器甚至会报警告信息。
场景三)
char *s1 = "hello";
char s2[] = "hello";
s1[0]='a'; //×运行ERROR( 这一句好像在一些的编译器不会出错,原因待查)
s2[0]='a'; //OK
分析:运行时会报错,原因在于企图改变s1的内容,由于s1指向的是常量字符串,其内容是不可修改的,因此在运行时不会通过。而s2指向的是变量区字符串,可以修改。
场景四)
让我们来给一个指针的指针赋值,在使用某些含char**参数的函数时会用到,场景二的增强版。
char *s1="hello";
char s2[]="hello";
char *s3=s2; //★注意这句必须要★
char **s4=&s3; //s2(char[])要用两步才能完成赋值
char **s5=&s1; //s1(char*) 只需一步
printf("s4=[%s]\n",*s4);//打印结果:s4=[hello]
printf("s5=[%s]\n",*s5);//打印结果:s5=[hello]
分析:这个例子应当说最能反映出char *与char []的差异,但是由于使用场合不多,新人尤其需要注意。
下面是一些char *s1 和 char s2[]相同的地方(同样编译器对char[]做了隐式变化):
1)作为形参完全相同
如:
void function(char *s1);
void function(char s1[]);
2)只读取不修改的时候
如:
char *s1="hello";
char s2[]="hello";
printf("s1[1]=[%c]\n",s1[1]); //s1[1]=[e]
printf("s2[1]=[%c]\n",s2[1]); //s2[1]=[e]
printf("s1=[%s]\n",s1); //s1=[hello]
printf("s2=[%s]\n",s2); //s2=[hello]
2. 二维指针**p怎么解释?
把两颗星看做一个整体符号吧,一个星的指针存放的是变量的地址。两颗星的指针存放的是指针的地址,这样理解一下。 举例:int i=5; int *p=&i; int **q=&p; 此时,一级指针p存放的是变量i的地址,通过p可以从地址层上操作i。 其次,二级指针q存放的是指针变量p的地址,通过q可以从地址层上去改变p的值,改变的p的值意味着什么?意味着p的指向发生了改变。 常见的情况用在二维数组比较多。
3.关于sort排序函数的调用:
sort函数的用法:
做ACM题的时候,排序是一种经常要用到的操作。如果每次都自己写个冒泡之类的O(n^2)排序,不但程序容易超时,而且浪费宝贵的比赛时间,还很有可能写错。STL里面有个sort函数,可以直接对数组排序,复杂度为n*log2(n)。使用这个函数,需要包含头文件<algorithm.h>。
这个函数可以传两个参数或三个参数。第一个参数是要排序的区间首地址,第二个参数是区间尾地址的下一地址。也就是说,排序的区间是[a,b)。简单来说,有一个数组int a[100],要对从a[0]到a[99]的元素进行排序,只要写sort(a,a+100)就行了,默认的排序方式是升序。
拿我出的“AC的策略”这题来说,需要对数组t的第0到len-1的元素排序,就写sort(t,t+len);
对向量v排序也差不多,sort(v.begin(),v.end());
排序的数据类型不局限于整数,只要是定义了小于运算的类型都可以,比如字符串类string。
如果是没有定义小于运算的数据类型,或者想改变排序的顺序,就要用到第三参数——比较函数。比较函数是一个自己定义的函数,返回值是bool型,它规定了什么样的关系才是“小于”。想把刚才的整数数组按降序排列,可以先定义一个比较函数cmp
bool cmp(int a,int b)
{
return a>b;
}
排序的时候就写sort(a,a+100,cmp);
假设自己定义了一个结构体node
struct node{
int a;
int b;
double c;
}
有一个node类型的数组node arr[100],想对它进行排序:先按a值升序排列,如果a值相同,再按b值降序排列,如果b还相同,就按c降序排列。就可以写这样一个比较函数:
以下是代码片段:
bool cmp(node x,node y)
{
if(x.a!=y.a) return x.a
if(x.b!=y.b) return x.b>y.b;
return return x.c>y.c;
}
排序时写sort(arr,a+100,cmp);
1. 函数参数 a[]和*a为啥是一样的?
即fun(char a[])和fun(char *a)是一样的
找了一个比较好的分析:
最近的项目中有不少c的程序,在与项目新成员的交流中发现,普遍对于char *s1 和 char s2[] 认识有误区(认为无区别),导致有时出现“难以理解”的错误。一时也不能说得很明白,网上也搜了一下相关文章发现一些写的比较好的,综合了一下当教育资料备用。
char *s1 = "hello";
char s2[] = "hello";
【区别所在】
char *s1 的s1,指针是指向一块内存区域,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。
char s2[]的s2 是数组对应着一块内存区域,其地址和容量(数组大小)在生命期里不会改变,只有数组的内容可以改变
【内存模型】
+-----+ +---+---+---+---+---+---+
s1: | *======> | h | e | l | l | o |\0 |
+-----+ +---+---+---+---+---+---+
+---+---+---+---+---+---+
s2: | h | e | l | l | o |\0 |
+---+---+---+---+---+---+
场景一)
char *s1 = "hello";
char s2[] = "hello";
s2=s1; //编译ERROR
s1=s2; //OK
分析:s2其地址和容量在生命期里不能改变
场景二)
char s2[] = "hello";
char *s1 = s2; //编译器做了隐式的转换 实际为&s2
或
char *s1 = &s2;
分析:以上两个指针复值完全等价,由于编译器会做这个隐式转换也容易导致初学者误认为 char *s 与char s[]是一回事。
另用第二种在一些编译器甚至会报警告信息。
场景三)
char *s1 = "hello";
char s2[] = "hello";
s1[0]='a'; //×运行ERROR( 这一句好像在一些的编译器不会出错,原因待查)
s2[0]='a'; //OK
分析:运行时会报错,原因在于企图改变s1的内容,由于s1指向的是常量字符串,其内容是不可修改的,因此在运行时不会通过。而s2指向的是变量区字符串,可以修改。
场景四)
让我们来给一个指针的指针赋值,在使用某些含char**参数的函数时会用到,场景二的增强版。
char *s1="hello";
char s2[]="hello";
char *s3=s2; //★注意这句必须要★
char **s4=&s3; //s2(char[])要用两步才能完成赋值
char **s5=&s1; //s1(char*) 只需一步
printf("s4=[%s]\n",*s4);//打印结果:s4=[hello]
printf("s5=[%s]\n",*s5);//打印结果:s5=[hello]
分析:这个例子应当说最能反映出char *与char []的差异,但是由于使用场合不多,新人尤其需要注意。
下面是一些char *s1 和 char s2[]相同的地方(同样编译器对char[]做了隐式变化):
1)作为形参完全相同
如:
void function(char *s1);
void function(char s1[]);
2)只读取不修改的时候
如:
char *s1="hello";
char s2[]="hello";
printf("s1[1]=[%c]\n",s1[1]); //s1[1]=[e]
printf("s2[1]=[%c]\n",s2[1]); //s2[1]=[e]
printf("s1=[%s]\n",s1); //s1=[hello]
printf("s2=[%s]\n",s2); //s2=[hello]
2. 二维指针**p怎么解释?
把两颗星看做一个整体符号吧,一个星的指针存放的是变量的地址。两颗星的指针存放的是指针的地址,这样理解一下。 举例:int i=5; int *p=&i; int **q=&p; 此时,一级指针p存放的是变量i的地址,通过p可以从地址层上操作i。 其次,二级指针q存放的是指针变量p的地址,通过q可以从地址层上去改变p的值,改变的p的值意味着什么?意味着p的指向发生了改变。 常见的情况用在二维数组比较多。
3.关于sort排序函数的调用:
sort函数的用法:
做ACM题的时候,排序是一种经常要用到的操作。如果每次都自己写个冒泡之类的O(n^2)排序,不但程序容易超时,而且浪费宝贵的比赛时间,还很有可能写错。STL里面有个sort函数,可以直接对数组排序,复杂度为n*log2(n)。使用这个函数,需要包含头文件<algorithm.h>。
这个函数可以传两个参数或三个参数。第一个参数是要排序的区间首地址,第二个参数是区间尾地址的下一地址。也就是说,排序的区间是[a,b)。简单来说,有一个数组int a[100],要对从a[0]到a[99]的元素进行排序,只要写sort(a,a+100)就行了,默认的排序方式是升序。
拿我出的“AC的策略”这题来说,需要对数组t的第0到len-1的元素排序,就写sort(t,t+len);
对向量v排序也差不多,sort(v.begin(),v.end());
排序的数据类型不局限于整数,只要是定义了小于运算的类型都可以,比如字符串类string。
如果是没有定义小于运算的数据类型,或者想改变排序的顺序,就要用到第三参数——比较函数。比较函数是一个自己定义的函数,返回值是bool型,它规定了什么样的关系才是“小于”。想把刚才的整数数组按降序排列,可以先定义一个比较函数cmp
bool cmp(int a,int b)
{
return a>b;
}
排序的时候就写sort(a,a+100,cmp);
假设自己定义了一个结构体node
struct node{
int a;
int b;
double c;
}
有一个node类型的数组node arr[100],想对它进行排序:先按a值升序排列,如果a值相同,再按b值降序排列,如果b还相同,就按c降序排列。就可以写这样一个比较函数:
以下是代码片段:
bool cmp(node x,node y)
{
if(x.a!=y.a) return x.a
if(x.b!=y.b) return x.b>y.b;
return return x.c>y.c;
}
排序时写sort(arr,a+100,cmp);
0 0
- ATL学习笔记02
- php学习笔记-02
- C#学习笔记02
- AJAX学习笔记02
- LUA 学习笔记 02
- ATL学习笔记02
- ExtJs学习笔记02
- Perl 学习笔记 --- 02
- Python 学习笔记02
- LINQ 学习笔记(02)
- Android学习笔记02
- libgdx学习笔记02
- Struts2学习笔记02
- Strus2学习笔记-02
- android学习笔记02
- java学习笔记02
- python学习笔记-02
- Java学习笔记 - 02
- C++中头文件(.h)和源文件(.cpp)都应该写些什么
- Linux下的一些I/O统计工具
- 洛谷1220关路灯
- 题目:复制带随机指针的链表
- Java Log4j配置说明
- 学习笔记02
- *LeetCode-Combination Sum
- 解决axis2处理java.util.Date类型对象时丢弃时间部分的问题
- JSON与XML的区别比较
- ViewPager的使用简单记录
- 使用gitk的时候中文显示乱码的问题
- 题目:子集
- hihocoder 1228 大模拟
- 【Android开发进阶】Android屏幕适配全攻略(最权威的官方适配指导)