从结构体到指针
//结构体 也是一种构造数据类型,之前我们学过的构造数据类型还有 枚举、数组
//结构体和数组很像,都是聚合变量,都可以存放一组数据,但是数组只能存放相同数据类型的数据,而结构体可以存放不同数据类型的数据。并且数组中的数据称为元素,结构体中的数据称为成员。
//定义结构体的语法格式:
/*
struct 结构体名称 {
类型说明符 成员1;
类型说明符 成员2;
...
类型说明符 成员n;
};
*/
struct student {
char name[20];//姓名
char gender;//性别
Zombie zom;
int age;//年龄
float score;//成绩
};
printf("student is %lu\n",sizeof(struct student));
//先定义结构体类型,再定义结构体变量
//结构体变量名是 stu,类型是 struct student
// struct student stu = {"heyifan", 'f', 18, 38.0};
//重定义的关键字是typedef
//type是 原有类型, name 是新类型
// typedef <#type#> <#name#>
typedef int Integer;
int a = 10;
Integer b = 20;
printf("a + b = %d\n",a + b);
int array[5] = {1, 2, 4, 6, 9};
typedef int Array[5];
Array arr = {1, 2, 4, 6, 9};
typedef struct student Student;
//Student 等价于 struct student
Student stu1 = {"hezhonger", 'f', 18, 38.0};
struct teacher {
char name[20];//姓名
int age;//年龄
char gender;//性别
char position[20];//职位
float salary;//薪水
} iOSTeacher = {"chenqingyuan", 28, 'm', "jiangshi", 100};//在定义结构体类型时 直接声明结构体变量
printf("iOSTeacher is %lu\n",sizeof(iOSTeacher));
struct {
char brand[20];//品牌
float price;//价格
float volumn;//容量
float weight;//重量
} cup = {"fuguang", 10.0, 500, 100};//匿名结构体,省略结构体名称,并且在定义结构体时,声明结构体变量。
// typedef struct zombie Zombie;
Zombie zom = {"tietong", 200, 5.0, 15};
//访问结构体成员使用.操作符,可以认为.就是 “的” 的意思
printf("zom's type is %s",zom.type);
zom.hp = 300;
// zom.type = "xueren";
strcpy(zom.type, "xueren");//如果想要修改 字符串(姓名、品牌、类型等等)不能直接赋值,需要使用字符串的拷贝函数strcpy()
printZombie(zom);
//例题
typedef struct zombie {
char type[20];//种类
int hp;//血量
float speed;//行走速度
float attack;//攻击力
}Zombie;
在.m文件中
//打印僵尸结构体的信息
void printZombie(Zombie zombie);
#import "Zombie.h"
void printZombie(Zombie zombie) {
printf("zombie type is %s, hp is %d, speed is %.2f, attack is %.2f\n",zombie.type, zombie.hp, zombie.speed, zombie.attack);
}
#import <Foundation/Foundation.h>
#import "Student.h"
int main(int argc, const char * argv[]) {
//创建一个结构体数组
Student students[5] = {
{"zhonger", 18, 31, 38.0},
{"zhubada", 17, 17, 10.0},
{"zuizui", 20, 2, 100.0},
{"hanghang", 22, 41, 60.0},
{"qiuxiang", 18, 13, 90.0}
};
printf("zhubada's number is %d\n",students[1].number);
printf("-----华丽的分割线-----\n");
//打印
for (int i = 0; i < 5; i ++) {
printStudent(students[i]);
}
printf("-----华丽的分割线-----\n");
Student maxStudent = findMaxScoreStudent(students, 5);
printStudent(maxStudent);
printf("-----华丽的分割线-----\n");
sortStudentsByScore(students, 5);
for (int i = 0; i < 5; i ++) {
printStudent(students[i]);
}
printf("-----华丽的分割线-----\n");
sortStudentsByName(students, 5);
for (int i = 0; i < 5; i ++) {
printStudent(students[i]);
}
return 0;
}
//学生的例题(结构体)
/创建一个学生的结构体
typedef struct student {
char name[20];//姓名
int age;//年龄
int number;//学号
float score;//成绩
}Student;
//打印学生信息
void printStudent(Student student);
//找到成绩最高的学生
Student findMaxScoreStudent(Student stus[], int count);
//将学生按照成绩从高到低排序
void sortStudentsByScore(Student stus[], int count);
//将学生按照姓名从低到高排序
void sortStudentsByName(Student stus[], int count);
#import "Student.h"
//打印学生信息
void printStudent(Student student) {
printf("student's name is %s, age is %d, number is %d, score is %.2f\n",student.name, student.age, student.number, student.score);
}
//找到成绩最高的学生
Student findMaxScoreStudent(Student stus[], int count) {
Student maxStu = {"", 0, 0, 0.0};
for (int i = 0; i < count; i ++) {
maxStu = maxStu.score > stus[i].score ? maxStu : stus[i];
}
return maxStu;
}
//将学生按照成绩从高到低排序
void sortStudentsByScore(Student stus[], int count) {
for (int i = 0; i < count - 1; i ++) {
for (int j = 0; j < count - 1 - i; j ++) {
if (stus[j].score < stus[j + 1].score) {
Student tempStu = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = tempStu;
}
}
}
}
//将学生按照姓名从低到高排序
void sortStudentsByName(Student stus[], int count) {
for (int i = 0; i < count - 1; i ++) {
for (int j = 0; j < count - 1 - i; j ++) {
if (strcmp(stus[j].name, stus[j + 1].name) > 0) {
Student tempStu = stus[j];
stus[j] = stus[j + 1];
stus[j + 1] = tempStu;
}
}
}
}
//指针
void sortArray(int *r, int count);
void sortArray(int *r, int count) {
for (int i = 0; i < count - 1; i ++) {
for (int j = 0; j < count - 1 - i; j ++) {
if (*(r + j) > *(r + j + 1)) {
int temp = *(r + j);
*(r + j) = *(r + j + 1);
*(r + j + 1) = temp;
}
}
}
}
int main(int argc, const char * argv[]) {
//指针,指针变量,此变量存储的内容是内存中某块内存的首地址。也就是我们所说的内存编号。
//我们通过指针可以间接访问到内存中存储的值,程序中需要的内容是值,而指针,也就是地址只是一个位置信息。
//指针变量所占内存大小只与操作系统位数有关,64位操作系统下,指针变量所占内存大小为8个字节。而内存编号对应的内存单元为一个字节。字节是内存的最小单位。
//既然指针也是变量,那么声明指针变量的语法格式 也是 数据类型 变量名 = 初值;
//在定义指针变量时,*挨着变量名。指针变量名通常以p、q、r开头。
int *p = NULL;//p 是指针变量名;NULL是初值,是一个空地址;int * 是指针变量的类型,代表p是一个整型指针,也就是说,p可以从首地址往下取四个字节大小的空间,获取里面的值。
//声明一个整型变量number,然后通过取址运算符获取到存储number的内存首地址,然后赋值给整型指针变量q
int number = 10;
int *q = &number;
printf("q is %p\n",q);//打印地址采用%p占位符。
int digital = 20;
q = &digital;//指针赋值相当于指针的重指向
*q = 200;//此时是取到digital变量保存的值,并且重新赋值为200
printf("digital is %d\n",digital);
/*
*的含义
1、如果*号出现在声明指针变量时,此时的*号仅仅是一个标识符,代表变量是一个指针变量。
2、如果*号与指针变量单独出现,比如*p,此时代表取值,取到p指向的内存区域中存储的值。
*/
//当指针做算数运算时,需要注意两个点
/*
1、+ - 决定了偏移是往内存地址高位还是低位移动,+是往高位,-是往低位
2、往高位还是低位移动多少个字节,是由指针类型决定的,如果是整型指针int *p = &a;,那么此指针算数运算p + 1或者p - 1,一次移动4个字节。
*/
/*
int a = 10, b = 20;
int *r = &a;
printf("a = %p, b = %p\n",&a, &b);
// *r, *r + 1,*(r - 1), r - 1;
printf("*r is %d, *r + 1 is %d, *(r - 1) is %d, r - 1 is %p\n",*r, *r + 1, *(r - 1), r - 1);
//指针与数组
int arr[10] = {0};
//数组名已经是数组的首地址,并且是数组第一个元素的首地址
printf("arr is %p, arr[0] is %p, &arr is %p\n",arr, &arr[0], &arr);
printf("arr + 1 is %p, &arr + 1 is %p\n",arr + 1, &arr + 1);
short array[2] = {3, 7};
int *p3 = array;
char *p4 = array;
printf("p3 is %d, p4 is %d",*p3, *p4);*/
//使用指针实现数组的冒泡排序
int array[10] = {0};
//随机赋值
for (int i = 0; i < 10; i ++) {
array[i] = arc4random() % (100 - 50 + 1) + 50;
printf("%d ",array[i]);
}
printf("\n");
//定义一个整型指针指向数组的首地址
int *r = array;
sortArray(r, 10);
for (int i = 0; i < 10; i ++) {
printf("%d ",*(r + i));
}
printf("\n");
//指针与字符串
char string[20] = "iPhone";
//定义一个字符指针指向声明好的字符串
char *s = string;
*(s + 1) = 'p';
printf("*s is %c, *s + 1 is %c, *(s + 1) is %c, s is %s, s + 1 is %s\n",*s, *s + 1, *(s + 1), s, s + 1);
// char *s1 = "iPhone";
// *(s1 + 1) = 'p';
//利用指针求字符串长度
//1、
int count = 0;
char *s2 = "iPhone6sPlus";
/*
while (*s2 != '\0') {
s2 ++;
count ++;
}
printf("count is %d\n",count);*/
//2、
while (*(s2 + count ++)) {}
printf("count is %d\n",count - 1);
//指针数组实现字符串排序
//数组name里面有三个字符型指针,分别指向三个字符串首地址
char *name[3] = {"iPhone", "plus", "hello"};
for (int i = 0; i < 3 - 1; i ++) {
for (int j = 0; j < 3 - 1 - i; j ++) {
if (strcmp(name[j], name[j + 1]) > 0) {
char *temp = name[j];
name[j] = name[j + 1];
name[j + 1] = temp;//地址是可以交换的,交换地址,相当于间接交换了字符串,因为不同地址访问到的字符串不一样
//此种写法是错误的,因为常量字符串是不能直接修改的,其次strcpy()一定要保证容量的问题。
// char temp[255] = {0};
// strcpy(temp, name[j]);
// strcpy(name[j], name[j + 1]);
// strcpy(name[j + 1], temp);
}
}
}
for (int i = 0; i < 3; i ++) {
printf("%s\n",name[i]);
}
return 0;
}
//内存管理
void func() {
int a = 10;
printf("%d ",a ++);
}
char * getAddress() {
char string[] = "iPhone";
return string;//当此函数执行完毕之后,string这个地址就已经不能访问了,因为这块空间已经被系统回收。当外界再去访问这块内存时,就会出现野指针。
//例如,金康达现在住在丽德酒店C208,四个月之后,搬走了,那么这间房就被回收了,如果四个月之后,还去开门,那就有可能看见不该看见的东西。
}
int main(int argc, const char * argv[]) {
//内存分区按照内存地址从高到低的顺序分为栈区、堆区、静态区(全局区)、常量区、代码区
//栈区:存放所有的局部变量,包括函数的形参
//栈区的特点:栈区的内存是由系统自动开辟和回收的,采用先进后出的管理原则管理局部变量,栈区变量只要函数执行完毕,就会被系统回收,所以返回栈区地址是一种非常愚蠢的操作。
//堆区:是系统留给开发者使用的内存。这块内存完全由程序猿把控。程序猿决定什么时候使用,使用多大,什么时候回收,系统不做任何干预。如果只开辟不回收,那么堆区域可用内存就会越来越少,当可用内存为0时,程序就会崩溃,crash。如果开辟回收之后,又去访问了这块内存空间,也会出现崩溃,叫做野指针。
//所以,堆区域的内存我们必须遵守一个原则,有开辟必须有释放,而且释放之后,不允许再去访问。
//静态区,也可以叫做全局区。主要用来存储静态变量以及全局变量。
//由系统为变量分配内存空间,程序猿不能控制,但是空间的回收只能当程序退出时才会执行。静态区的变量,有一个特点,初始化只有一次,而且并不会随着函数的执行完毕被回收。
//常量区:存放系统内部所有的常量 比如 10、4.5、’a‘、“iPhone”
//我们不会对常量区进行修改或者操作,一旦改了常量区的内容,程序会立即崩溃。常量区中的内容只有一份,并且是只读的。
//代码区:代码区存放的不是源代码,函数都存放在栈区,代码区存放的是源代码编译之后形成的可执行文件,也可以叫做二进制流文件,或者CPU指令。
for (int i = 0; i < 10; i ++) {
func();
}
//堆区域分配函数
//1、malloc,作用是开辟一段给定字节大小的堆区域空间,并且返回该内存空间的首地址,void *不是空指针,而是泛型指针,根据需求来给定类型
char *str = malloc(8);
strcpy(str, "iPhone");
printf("*str is %c, *(str + 1) is %c, *str + 1 is %c, str is %s, str + 2 is %s\n",*str, *(str + 1), *str + 1, str, str + 2);
int *q = malloc(sizeof(int) * 3);
q[0] = 12;
*(q + 1) = 13;
q[2] = 14;
for (int i = 0; i < 3; i ++) {
printf("number is %d\n",*(q + i));
}
free(q);//free将堆区域开辟好的空间回收,标记为不可用。
short *r = malloc(sizeof(short) * 6);
/*
有一已知字符串,其中包含 数字 字符,提取其中的 数字字符 ,要求动态分配内存保存。
提示: 先计算出有几个数字字符,然后根据数字字符的个数在堆区开辟空间。*/
/*
char string[] = "i12Ph34on56e";
//定义循环增量 以及 计数变量
int i = 0, count = 0;
//遍历字符串,得到数字字符的个数
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
count ++;
}
i ++;
}
printf("count is %d\n",count);
//动态分配内存保存数字
int *number = malloc(sizeof(int) * count);
i = 0;//让循环增量变为0,遍历重新开始。
int j = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
*(number + j) = string[i] - '0';
j ++;
}
i ++;
}
for (int i = 0; i < count; i ++) {
printf("number is %d\n",*(number + i));
}
free(number);*/
//输入3个单词,动态分配内存保存单词,并在最后输出。
//定义一个包含三个指针变量的数组,来存储开辟的堆区域空间首地址
char *words[3] = {0};
char temp[255] = {0};//定义一个字符数组来接收,用户每一次输入的字符串。
printf("请输入三个字符串(中间以空格隔开):");
for (int i = 0; i < 3; i ++) {
scanf("%s",temp);
unsigned long length = strlen(temp);//先获取输入的字符串长度
words[i] = malloc(length + 1);//动态分配内存
strcpy(words[i], temp);//将输入的字符串拷贝进堆区域。
}
for (int i = 0; i < 3; i ++) {
printf("%s\n",words[i]);
free(words[i]);//释放
}
// memset()重置函数
int *number = malloc(sizeof(int) * 5);
//从number首地址开始将sizeof(int) * 5的空间上的每一个字节全部置空为0
memset(number, 0, sizeof(int) * 5);
//memcmp() 内存比较函数,比较的不是内存大小,而是内存中存储的值的大小
char *str1 = "iPhone";
char *str2 = "iPhoneplus";
int result = memcmp(str1, str2, 7);//四代表比较内存中前四个字节中的值
printf("result is %d\n",result);
int *number1 = malloc(4);
*number1 = 10;
int *number2 = malloc(4);
*number2 = 11;
int result1 = memcmp(number1, str1, 4);
printf("result is %d\n",result1);
return 0;
}
void func() {
int a = 10;
printf("%d ",a ++);
}
char * getAddress() {
char string[] = "iPhone";
return string;//当此函数执行完毕之后,string这个地址就已经不能访问了,因为这块空间已经被系统回收。当外界再去访问这块内存时,就会出现野指针。
//例如,金康达现在住在丽德酒店C208,四个月之后,搬走了,那么这间房就被回收了,如果四个月之后,还去开门,那就有可能看见不该看见的东西。
}
int main(int argc, const char * argv[]) {
//内存分区按照内存地址从高到低的顺序分为栈区、堆区、静态区(全局区)、常量区、代码区
//栈区:存放所有的局部变量,包括函数的形参
//栈区的特点:栈区的内存是由系统自动开辟和回收的,采用先进后出的管理原则管理局部变量,栈区变量只要函数执行完毕,就会被系统回收,所以返回栈区地址是一种非常愚蠢的操作。
//堆区:是系统留给开发者使用的内存。这块内存完全由程序猿把控。程序猿决定什么时候使用,使用多大,什么时候回收,系统不做任何干预。如果只开辟不回收,那么堆区域可用内存就会越来越少,当可用内存为0时,程序就会崩溃,crash。如果开辟回收之后,又去访问了这块内存空间,也会出现崩溃,叫做野指针。
//所以,堆区域的内存我们必须遵守一个原则,有开辟必须有释放,而且释放之后,不允许再去访问。
//静态区,也可以叫做全局区。主要用来存储静态变量以及全局变量。
//由系统为变量分配内存空间,程序猿不能控制,但是空间的回收只能当程序退出时才会执行。静态区的变量,有一个特点,初始化只有一次,而且并不会随着函数的执行完毕被回收。
//常量区:存放系统内部所有的常量 比如 10、4.5、’a‘、“iPhone”
//我们不会对常量区进行修改或者操作,一旦改了常量区的内容,程序会立即崩溃。常量区中的内容只有一份,并且是只读的。
//代码区:代码区存放的不是源代码,函数都存放在栈区,代码区存放的是源代码编译之后形成的可执行文件,也可以叫做二进制流文件,或者CPU指令。
for (int i = 0; i < 10; i ++) {
func();
}
//堆区域分配函数
//1、malloc,作用是开辟一段给定字节大小的堆区域空间,并且返回该内存空间的首地址,void *不是空指针,而是泛型指针,根据需求来给定类型
char *str = malloc(8);
strcpy(str, "iPhone");
printf("*str is %c, *(str + 1) is %c, *str + 1 is %c, str is %s, str + 2 is %s\n",*str, *(str + 1), *str + 1, str, str + 2);
int *q = malloc(sizeof(int) * 3);
q[0] = 12;
*(q + 1) = 13;
q[2] = 14;
for (int i = 0; i < 3; i ++) {
printf("number is %d\n",*(q + i));
}
free(q);//free将堆区域开辟好的空间回收,标记为不可用。
short *r = malloc(sizeof(short) * 6);
/*
有一已知字符串,其中包含 数字 字符,提取其中的 数字字符 ,要求动态分配内存保存。
提示: 先计算出有几个数字字符,然后根据数字字符的个数在堆区开辟空间。*/
/*
char string[] = "i12Ph34on56e";
//定义循环增量 以及 计数变量
int i = 0, count = 0;
//遍历字符串,得到数字字符的个数
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
count ++;
}
i ++;
}
printf("count is %d\n",count);
//动态分配内存保存数字
int *number = malloc(sizeof(int) * count);
i = 0;//让循环增量变为0,遍历重新开始。
int j = 0;
while (string[i] != '\0') {
if (string[i] >= '0' && string[i] <= '9') {
*(number + j) = string[i] - '0';
j ++;
}
i ++;
}
for (int i = 0; i < count; i ++) {
printf("number is %d\n",*(number + i));
}
free(number);*/
//输入3个单词,动态分配内存保存单词,并在最后输出。
//定义一个包含三个指针变量的数组,来存储开辟的堆区域空间首地址
char *words[3] = {0};
char temp[255] = {0};//定义一个字符数组来接收,用户每一次输入的字符串。
printf("请输入三个字符串(中间以空格隔开):");
for (int i = 0; i < 3; i ++) {
scanf("%s",temp);
unsigned long length = strlen(temp);//先获取输入的字符串长度
words[i] = malloc(length + 1);//动态分配内存
strcpy(words[i], temp);//将输入的字符串拷贝进堆区域。
}
for (int i = 0; i < 3; i ++) {
printf("%s\n",words[i]);
free(words[i]);//释放
}
// memset()重置函数
int *number = malloc(sizeof(int) * 5);
//从number首地址开始将sizeof(int) * 5的空间上的每一个字节全部置空为0
memset(number, 0, sizeof(int) * 5);
//memcmp() 内存比较函数,比较的不是内存大小,而是内存中存储的值的大小
char *str1 = "iPhone";
char *str2 = "iPhoneplus";
int result = memcmp(str1, str2, 7);//四代表比较内存中前四个字节中的值
printf("result is %d\n",result);
int *number1 = malloc(4);
*number1 = 10;
int *number2 = malloc(4);
*number2 = 11;
int result1 = memcmp(number1, str1, 4);
printf("result is %d\n",result1);
return 0;
}
typedef struct student {
char name[20];
int age;
float score;
}Student;
//求两个整数的和 以及 求两个整数的最大值
int sum(int a, int b);
int maxValue(int a, int b);
typedef int (*PFUN)(int, int);
void printHello();
int getValue(int a, int b, PFUN p);
void replace(char destination[], char source[]);//替换
void match(char destination[], char source[]);//拼接
typedef void (*PF)(char [], char []);
void printStudent(Student student);
void markStudent(Student stus[], int count, char *str, PF p);
int sum(int a, int b) {
return a + b;
}
int maxValue(int a, int b) {
return a > b ? a : b;
}
void printHello() {
printf("hello world\n");
}
int getValue(int a, int b, PFUN p) {
return p(a, b);
}
void replace(char destination[], char source[]) {
strcpy(destination, source);
}//替换
void match(char destination[], char source[]) {
strcat(destination, source);
}//拼接
void printStudent(Student student) {
printf("%s %d %.2f\n",student.name, student.age, student.score);
}
void markStudent(Student stus[], int count, char *str, PF p) {
for (int i = 0; i < count; i ++) {
if (stus[i].score > 90.0) {
p(stus[i].name, str);
}
}
}
posted on 2016-01-29 19:57 沈少磊5436238 阅读(313) 评论(0) 收藏 举报
浙公网安备 33010602011771号