练习:
char *p = “abcde”;
char a[] = “abcde”;
int i = strlen(p);
int j = strlen(a);
int m = sizeof(p);
int n = sizeof(a);
i, j, m, n的值分别为:__5____、__5____、4____、____6。
注意
char a[4] = "abc";
strcpy(a,"end");//栈区 ok
char *a = "abc";//字符串常量,存在常量区,只读
strcpy(a,"end"); // error
递归函数练习
1、Fib 1 1 2 3 5 8 ...
int fib_func(int n){//n代表是第几个数
if(1==n||2==n){
return 1;
}
else{
return fib_func(n-1)+fib_func(n-2);
}
}
2、求自然数的和 n+(n-1)+(n-2)+...+0
int my_sum(int n){
if(0==n){
return 0;
}
else{
return my_sum(n-1)+n;
//3 sum(2)+1 sum(1)+1 +1 sum(0)+1 +1 +1
//4 sum(3)+1 sum(2)+2 sum(1)+3 sum(0)+4
}
}
3、使用递归实现strlen
//一维数组作为函数的形参
//char *arr
//char arr[]
//arr[8]=====*(arr+8)
int my_strlen(char *arr){//char arr[]
if(*arr==0){
return 0;
}
else{
return 1+my_strlen(arr+1);
}
}
int my_strlen2(char arr[],int n){//char arr[]
if(arr[n]){
//arr++;
return my_strlen2(arr,n+1);
}
else{
return n;
}
}
优点:代码简洁,实现方便
缺点:效率低,容易导致栈溢出。
指针常量和常量指针
指针常量——(类型 const p)
----指针的指向不可以更改,但是可以通过p间接修改其所对应的变量的值。
常量指针——(const 类型 *p或者 类型 const p)
----指针可以指向其他的变量,但是不能通过p间接修改其所对应的变量的值。
// const int a=10;
// a=50;
int b=90;
int a[10]={0};
int c[10]={0};
int const *p=&a[0];//常量指针,
// p[7]=10;
//*p=20;
//常量指针,不能通过p去修改a
int *const q=&c;//指针常量
q=&a;
*(q+6)=30;
// q=&b;
//q的指向不能更改
const int *const m_p=&a;
// *m_p=30;
// m_p=&b;
//m_p的指向不能更改并且也不能通过m_p去修改a.
练习:
有以下表达式:
int a=248, b=4;
int const c=21;
const int *d=&a;
int *const e=&b;
int const *const f =&a;
请问下列表达式哪些会被编译器禁止?为什么?
c=32;
d=&b;
*d=43;
e=34;
e=&a;
f=0x321f;
数组与指针
int a[10]={0};
int *p=a;//没有改变p指向的内存地址
p[5]=30;
*(p+4)=90;//没有改变p指向的内存地址
p+=7;
*p=35;//改变lp指向的内存地址
问p[2]=100;修改的是哪个元素?
结构体
定义以及成员初始化
p1=p2;//可以 浅拷贝,按照字节依次进行赋值,
//有指针容易出错 堆内存申请,会发生同一内存的重复释放
注意:结构体不能比较大小,因为有垃圾字节填充,对齐原则的存在。
结构体数组
练习:
学生结构体数组排序 按照年龄进行冒泡排序,年龄相同的按照分数排序。
指针与二维数组
1、 a+1 指向的是第一行的元素,也就是指向一个一维数组
2、 a[1] 指向的是第一行,第0列的元素的地址
3、 *(a+1) 指向的是第一行,第0列的元素的地址
4、 a[1]+2 指向的是第一行的第二列的元素的地址
5、 *(a+1)+2 指向的是第一行的第二列的元素的地址
6、 *(a[1]+2) 指向的是第一行的第二列的元素
7、 ((a+1)+2) 指向的是第一行的第二列的元素
注意:
二位数组的名字代表的是二级指针;
[]可以等同理解为解引用(类似于* 的解引用的方式)