完了,要重新学习C语言了。
指针是能存放其他变量地址的变量;
# include <stdio.h>
int main(void)
{
int * p; //p是变量的名字, int * 表示p变量存放的是int类型变量的地址
int i = 3;
p = &i; //OK
//p = i; //error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值
//p = 55; //error 原因同上
return 0;
}
1.p保存了i的地址,p可以指向i;此时i和p等价。也就是说,如果p指向i,那么p就等于i,不能说它是i的地址,或者说i的值,它就是i本身。i和*p能在任何值地方变。
2.但是p不是i,i也不是p;修改p的值不改变i的值,修改i的值也不改变p的值;
3.如果一个指针变量指向了某个普通变量,则 指针变量就完全等同于普通变量;
eg:
如果p是个指针变量,并且p存放了普通变量i的地址,
则如果p指向了普通变量i,则
p就完全等同于i
或者说,在所有出现p的地方都可以替换成i;
在所有出现i的地方都可以替换成p;
int * p; // 不表示定义了一个名字叫*p的变量;而是指的是:
p是变量名,p变量名的数据类型是int 类型;
所谓int类型,实际上就是存放了int变量地址的类型;
指针变量也是变量,只不过它存放的不是内存单元的内容,只能存放内存单元的地址;
普通变量之前不能加*,常量和表达式之前不能加&;
指针就是地址,地址就是指针;
地址就是内存单元的编号;
指针变量是存放地址的变量;
指针和指针变量是两个不同的概念;
但是要注意,通常我们在叙述的时候会把指针变量简称为指针,但是实际上他们的意义是不一样的;
int i = 10;
int *P = &i // 等价于int *p p = &i;
指针的重要性:
表示一些复杂的数据结构;
快速的传递数据;
使函数返回一个以上的值;
能直接访问硬件;
能够方便处理字符串;
是理解面向对象语言的基础;
总结:指针是C语言的灵魂。
指针的定义:
地址:内存单元的编号;
从零开始的非负整数;
指针就是地址,地址就是指针;
地址就是内存单元的编号;
指针就是地址,地址就是指针;
指针变量是存放地址的变量;
指针和指针变量是两个不同的概念;
但是要注意,通常我们在叙述的时候会把指针变量简称为指针,但是实际上他们的意义是不一样的;
指针的本质是一个操作受限的非负整数;
指针的分类:
1.基本类型指针
# include <stdio.h>
int main(void)
{
int * p; //p是变量的名字, int * 表示p变量存放的是int类型变量的地址
//int * p; 不表示定义了一个名字叫做*p的变量
// int * p; 应该这样理解: p是变量名, p变量的数据类型是 int *类型
// 所谓int * 类型 实际就是存放int变量地址的类型
int i = 3;
int j;
p = &i;
/*
1. p保存了i的地址, 因此p指向i
2. p不是i,i也不是p,更准确的说: 修改p的值不影响i的值,修改i的值也不会影响p的值
3. 如果一个指针变量指向了某个普通变量, 则
*指针变量 就完全等同于 普通变量
例子:
如果p是个指针变量,并且p存放了普通变量i的地址
则p指向了普通变量i
*p 就完全等同于 i
或者说: 在所有出现*p的地方都可以替换成i
在所有出现i的地方都可以替换成*p
*p 就是以p的内容为地址的变量
*/
j = *p; //等价于 j = i;
printf("i = %d, j = %d\n", i, j);
return 0;
}
一个用指针互换两个数字的code:
# include <stdio.h>
void swap_1(int , int );//函数声明的时候一般不写形参;
void swap_2(int * , int * );
void swap_3(int * , int * );
int main(void)
{
int a = 3;
int b = 5;
swap_3(&a,&b);
printf("a = %d, b = %d\n", a, b);
return 0;
}
void swap_1(int i, int j)
{
int t;
t = i; i = j; j = t;
}
void swap_2(int * p, int * q) //形参名字是p和q,接收实参数据的是p和q,而不是*p和*q
{
int * t; //如果要 互换p q的值,则一定是*t而不是t,因为数据类型要保持一致;
t = p; p = q; q = t;
}// 函数2还是无法互换ab,因为这只是互换了pq的地址,所以相当于互换了pq的值,但是ab是静止量,是无法互换ab的地址的。
void swap_3(int * p, int * q) //形参名字是p和q,接收实参数据的是p和q,而不是*p和*q
{
int t;
t = *p; *p = *q; *q = t; //p是int * , *p是是int;
}
的含义:
1.乘法;
2.定义指针变量;//定义了一个叫做p的变量,int表示只能存放int变量的地址;
3.指针运算符;//该运算符放在已经定义好的指针变量的前面,如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量;
如何通过被调函数修改主调函数普通变量的值:
1.实参必须为该普通变量的地址;
2.形参必须是指针变量;
3.在被调函数中通过
*形参名=…
就可以修改主调函数中相关变量的值;
- 指针和数组:
指针和一维数组:
数组名:
一维数组名是个指针常量;
它存放的是一维数组的第一个元素的地址;
它的值不能被改变;
一维数组名指向的是数组的第一个元素;
*a[i] 和 (a+i)一样;// 这个要记住
eg:
# include <stdio.h>
int main(void)
{
int a[5]; //a是数组名 5是数组元素的个数 元素就是变量 a[0] -- a[4]
// int a[3][4]; //3行4列 a[0][0]是第一个元素 a[i][j]第i+1行j+1列
int b[5];
//a = b;//error a是常量
printf("%#X\n", &a[0]);
printf("%#X\n", a);
return 0;
}
/*
在Vc++6.0中的输出结果是:
--------------
0X12FF6C
0X12FF6C
Press any key to continue
--------------
总结:
一维数组名
一维数组名是个指针常量
它存放的是一维数组第一个元素的地址
*/
下标和指针的关系:
如果p是个指针变量,则
p[i]永远等价于*p(i+1)
确定一个一维数组最少需要两个参数;
数组第一个元素的地址;
数组的长度;
- 结构体:
为什么需要结构体:
为了表示一些复杂的事物,而普通的基本类型无法满足实际要求;
什么叫结构体:
把一些基本类型数据组合形成的一个新的复合数据类型,这个就叫做结构体;
eg:
# include <stdio.h>
struct Student
{
int age;
float score;
char sex;
};
int main(void)
{
struct Student st = {80, 66.6, 'F'};
/* int age;
float score;
char sex;
int age2;
float score2;
char sex2;
*/
return 0;
}
怎么样使用结构体和变量:
- 赋值和初始化:
# include <stdio.h>
//第一种方式
struct Student
{
int age;
float score;
char sex;
};
int main(void)
{
struct Student st = {80, 66.6, 'F'}; //初始化 定义的同时赋初值
struct Student st2;//先定义,再初始化
st2.age = 10;
st2.score = 88;
st2.sex = 'F';
printf("%d %f %c\n", st.age, st.score, st.sex);
printf("%d %f %c\n", st2.age, st2.score, st2.sex);
return 0;
}
定义的时候可以整体赋值;
如果定义完了之后,则只能单个的赋值;
如何提取出结构体变量中的每一个成员:
1. 结构体变量名.成员名
2. 指针变量名->成员名
eg:
# include <stdio.h>
//第一种方式
struct Student
{
int age;
float score;
char sex;
};
int main(void)
{
struct Student st = {80, 66.6, 'F'}; //初始化 定义的同时赋初值
struct Student *pst=&st; //&st不能改为st;
st.age = 10;//第一种方式初始化;
pst->age=10;//第二种方式;
printf("%d %f %c\n", st.age, st.score, st.sex);
printf("%d %f %c\n", st2.age, st2.score, st2.sex);
return 0;
}
pst->age在计算机内部会被转化成(*pst).age
pst->age所指向的那个结构体变量中的age的成员;
# include <stdio.h>
struct Student
{
int age;
char sex;
char name[100];
}; //分号不能省
// 上面仅仅只是定义了一个数据类型,定义了一个叫结构体的数据类型;数据类型的名字叫struct Student
//有三个成员
int main(void)
{
struct Student st = {20, 'F', "小娟"};//定义变量,并赋初始值;
struct Student * pst = &st;
printf("%d %c %s\n", st.age, st.sex, st.name);
printf("%d %c %s\n", pst->age, pst->sex, pst->name); //pst->age 转化成 (*pst).age 等价于 st.age
return 0;
}
/*
2009年11月24日9:17:43
通过函数完成对结构体变量的输入和输出
*/
# include <stdio.h>
# include <string.h>
struct Student
{
int age;
char sex;
char name[100];
}; //分号不能省
void InputStudent(struct Student *);
void OutputStudent(struct Student ss);
int main(void)
{
struct Student st; //15行
InputStudent(&st); //对结构体变量输入 必须发送st的地址
// printf("%d %c %s\n", st.age, st.sex, st.name);
OutputStudent(st); //对结构体变量输出 可以发送st的地址也可以直接发送st的内容
return 0;
}
void OutputStudent(struct Student ss)
{
printf("%d %c %s\n", ss.age, ss.sex, ss.name);
}
void InputStudent(struct Student * pstu) //pstu只占4个字节
{
(*pstu).age = 10;
strcpy(pstu->name, "张三");
pstu->sex = 'F';
}
/*
//本函数无法修改主函数15行st的值 所以本函数是错误的
void InputStudent(struct Student stu)
{
stu.age = 10;
strcpy(stu.name, "张三"); //不能写成 stu.name = "张三";
stu.sex = 'F';
}
*/
指针的优点:
/*
2009年11月24日9:17:43
示例:
发送地址还是发送内容
目的:
指针的优点之一:
快速的传递数据,
耗用内存小
执行速度快
*/
# include <stdio.h>
# include <string.h>
struct Student
{
int age;
char sex;
char name[100];
}; //分号不能省
void InputStudent(struct Student *);
void OutputStudent(struct Student *);
int main(void)
{
struct Student st ; //15行
//printf("%d\n", sizeof(st));
InputStudent(&st); //对结构体变量输入 必须发送st的地址
OutputStudent(&st); //对结构体变量输出 可以发送st的地址也可以直接发送st的内容 但为了减少内存的耗费,也为了提高执行速度,推荐发送地址
return 0;
}
void OutputStudent(struct Student *pst)
{
printf("%d %c %s\n", pst->age, pst->sex, pst->n me);
}
void InputStudent(struct Student * pstu) //pstu只占4个字节
{
(*pstu).age = 10;
strcpy(pstu->name, "张三");
pstu->sex = 'F';
}
/*
//本函数无法修改主函数15行st的值 所以本函数是错误的
void InputStudent(struct Student stu)
{
stu.age = 10;
strcpy(stu.name, "张三"); //不能写成 stu.name = "张三";
stu.sex = 'F';
}
*/
结构体变量不能相加,不能相减,不能乘除,只能相互赋值。
- 枚举:
把一个事物所有的可能的取值一一列举出来;
枚举的优点:
使代码更安全;
# include <stdio.h>
//只定义了一个数据类型,并没有定义变量, 该数据类型的名字是 enum WeekDay
enum WeekDay
{
MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturDay, SunDay
};
int main(void)
{
//int day; //day定义成int类型不合适
enum WeekDay day = SunDay;
printf("%d\n", day);
return 0;
}
- 链表:
没看懂;
位运算符:
&; //按位与;
&& //逻辑与;
i&j //把i和j的每一位进行相与;
i&&j //i并且j,最后输出的只能是1或0;
| //按位或;
|| //逻辑或;
~ //按位取反;
^ //按位异或; //相同为0,不同为1;
<< //按位左移;
>> //按位右移;
二进制数左移n位相当于乘2^n,右移n位相当于除2的n次方;