黑马程序员——ios开发基础之C语言数组、指针与结构体

时间:2021-07-31 00:23:39
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

第一讲  数组

一、数组的基本概念

                相同类型 若干个 有序
                由若干个相同类型的数据组成的有序的集合。           
                有序:存储地址连续           下标连续
                 数组名:用来存放数组首地址的常量
                 数组元素:构成数组的每一个数据 
                 数组的下标:给数组的每一个元素做一个编号
                 数组的长度:构成数组的数据的个数

二、一维数组

                 数组的使用的流程:先定义 ---> 初始化 --->使用

        1、数组定义(如果不初始化里面存放的是垃圾值)

                 格式: int arr[10];
                 定义长度为10的整型数组,每个都是Int型的,数组的名称 arr
                             float  f1[12];         char c[10];
                1) 定义变量的同时,可以定义数组         int a[10],b,c;
                2) int a1[3+2];
                3) int n=5; int a2[n]; //其他编译器数组定义的时候,数组长度不能使用变量,但是xcode做了优化,这是可以的
                4) #define N 5 int a3[N+3];
                5) int a4; int a4[10]; 数组的名称不能和变量名重名
                6)数组名的命名原则严格遵守标示符命名原则

         2、初始化

                 数组中,一旦有一个元素被初始化了,其他元素也都被初始化了
                  1)定义的时候初始化
                                int a[10] = {0};
                       (1) 完全初始化(数组的每一个元素都被初始化了)
                                int a[3]={2,3,4}; //完全初始化 a[0]=2,a[1]=3,a[2]=4
                            不指定数组长度的完全初始化
                                int a1[]={2,3,34,4}; //定义int型数组a1,初始化值为2, 3, 34, 4,根据初始化的值,确定数组的长度
                     (2)部分初始化(只指定数组的一部分初始化值)
                                int a2[10]={0} //相当于有a2所有的元素都初始化为0
                                int a3[5]={1,2,3};
                             指定下标的数组元素的初始化
                                int a4[6]={[3]=100,[0]=23};     //a[3]=100,a[0]=23;没有初始化的值,系统自动初始化为0
                   2)先定义,后初始化
                                int a5[10];
                                a5[0]=1;
                                a5[1]=2;
                                     ...
                                a5[9]=100;

         3、数组的引用

                       取出数组中存放的内容,数组只能通过数组的下标来获取对应的内容
                               int a[n];
                       下标的范围: 0 ~ (n-1)
                      越界(越界访问):访问的数组元素的下标超出了最大的下标
                        int a6[3]={1,2,3,4,5};(危险的)

        4、数组的存储方式

                    1)数组在内存中分配的时连续的一片内存空间
                    2)数组的名称存放连续内存空间的首地址
                    3)数组的第一个元素存放到数组内存的低地址(首地址)
                    4)首地址 = &a[0] = a

        5、计算数组的长度

                   1) int a[5];
                   2) int a[]={1,2,3,34,6,6,67};
                数组占用总得存储空间
                       sizeof(a);
                计算数组的元素的个数(长度)
                       sizeof(a)/sizeof(int)

        6、数组和函数之间的关系

                  1) 数组的元素作为函数的参数(实参)
                             int a[3]={1,2,3};
                             int sum(int x,int y){
                                    return x+y;
                                }
                             sum(a[0],a[1]);
                          注意:值传递
                  2)数组名作为函数的参数(实参)
                             void sum(int s[]){
                              }
                                sum(a); // int s[]; s=a; s存放了a得地址,相当于s和a都指向了同一块内存区域, 操作s等同于操作a
                          注意:地址的传递

                 应用一:数组遍历:正序、逆序输出数组元素

              #include<stdio.h>
int main(){
int a[10]={1,2,3,4,5,6,7,8,9,10};
for(int i=0;i<=9;i++) //正序输出
printf("%d",a[i]);
printf("\n");
for(int j=9;j>=0;j--) //逆序输出
printf("%d",a[j]);
return 0;
}

               应用二: 从键盘获取10个数,放进数组中,找出最大值

               #include<stdio.h>
int main(){
int i,max,a[10];
printf("请输入10个数:\n");
for(int i=0;i<10;i++)
scanf("%d",&a[i]);
max=a[0];
for(int i=0;i<10;i++)
if(a[i]>max) max=a[i];
printf("%d\n",max);
return 0;
}

三、几个算法

    1、冒泡排序

             1)比较相邻的元素。如果第一个比第二个大,就交换他们两个。
             2)对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应
                  该会是最大的数。
             3)针对所有的元素重复以上的步骤,除了最后一个。
             4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
          冒泡方式:大数下沉(每一趟最大的数跑到最后一个元素中)      小数上浮
          冒泡举例:
#include <stdio.h>

int main(int argc, char *argv[])
{
int a[]={12,2,3,56,1};
int len = sizeof(a)/sizeof(int);
for(int i=0;i<len-1;i++){ //外层循环控制趟数
for(int j=0;j<len-i-1;j++){ //里层循环控制次数,每趟排序都会确定一个数,所以需要再循环len-i次,但因为每次都是
//相邻的两个数进行比较,为了a[j+1]不越界,让j循环到len-i-1时停止。
int temp;
if(a[j]>a[j+1]){
temp = a[j];
a[j] = a[j+1]; //如果条件满足就交换两个相邻元素的值
a[j+1] = temp;
}
}
}
for(int i=0;i<len;i++)
printf("%d\t",a[i]);
return 0;
}
                 分析:排序前                                  第一趟 i=0                     第二趟 i=1                 第三趟 i=2                  第四趟 i=3                             
                           0   1  2  3   4                       j=len-1-0=4                     j=len-1-1=3                j=len-1-2=2                 j=len-1-3=1                                
                          12  2  3  56 1                  1) 2 12 3 56 1               1)2 3 12 1 56             1)2 3 1 12 56           1)1 2 3 12 56                               
                                                                 2) 2 3 12 56 1              2)2 3 12 1 56             2)2 1 3 12 56                                              
                                                                 3) 2 3 12 56 1               3)2 3 1 12 56                                                                                                 
                                                                 4) 2 3 12 1 56                                                                                                                                             

     2、选择排序

            选择排序不再是相邻的两个元素比较了。它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩               余未排序元素中继续寻找最小元素,然后放到排序序列第二个位置。以此类推,直到所有元素均排序毕。             代码实现:
#include <stdio.h>

int main(int argc, char *argv[])
{
int a[]={12,2,3,56,1};
int len = sizeof(a)/sizeof(int);
//每一趟都是拿着一个元素与后面其他元素进行比较,找出最小值
// 1、确定需排序趟数
for (int i = 0 ; i < len - 1; i++) {
// 2、每一趟怎么处理
for (int j = i + 1; j < len; j++) {
if (a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
for(int i=0;i<len;i++)
printf("%d\t",a[i]);
return 0;
}

     3、折半查找

              1)思路                     在有序序列中,取中间元素作为比较对象,若给定值与中间元素的要查找的数相等,则查找成功;若给定值小于中间元 素的要查找的数, 则在中间元素的左半区继续查找;若给定值大于中间元素的要查找的数,则在中间元素的右半区继续查找。不断重复上述查找过程,直到查找成功,或所查找的区域无数据元素,查找失败。                   2)步骤                           ① low=1; high=length; // 设置初始区间
                          ② 当low>high 时,返回查找失败信息// 表空,查找失败
                          ③ low≤high, mid=(low+high)/2; // 取中点
                                           a. 若key<arr[mid],high=mid-1;转 ③ // 查找在左半区进行
                                           b. 若key>arr[mid],low=mid+1;转 ③ // 查找在右半区进行
                                           c. 若key=arr[mid],返回数据元素在表中位置// 查找成功
             3)应用举例:在下面数组中查找数字2的位置
         #include <stdio.h>

int main(int argc, char *argv[]){
int key=2,min = 0;
int a[]= {1,2,3,12,56};
int len = sizeof(a)/sizeof(int);
int max = len-1;
for (int i=0; i<len; i++) {
printf("%d \t",arr[i]);
}
printf("\n");
while (min<=max) { //③
int mid = (max+min)/2;
if (a[mid]>key) { //a
max = mid-1;
}else if (a[mid]<key){ //b
min = mid+1;
}else{
printf("%d\n",mid); //c
}
}
return 0;
}

四、二维数组


       1、概念

              二维数组即一维数组的每一个元素又是一个一维数组(嵌套)形成的数组。

       2、定义和初始化

               1)定义的时候初始化
                       数据类型  数组名[常量表达式1][常量表达式2]
                         int a1[3][2]={1,2,3,4,5,6};
                         int a2[3][2]={{1,2},{3,4},{5,6}};
                         int a5[3][3]={{1},{2},{3}};//相当于下面的数字矩阵
                                                                 //1 0 0
                                                                   2 0 0
                                                                   3 0 0
                        int a7[3][3]={{[1]=34},{[0]=10},{[2]=29}};
                        int a8[3][3]={[2][2]=12};
                                                               //0 34 0
                                                                10 0 0
                                                                 0 0 29
                   二维数组支持定义的时候,不指定第一维长度
                          int a8[][2]={1,2,3,4,5,6};
             2)先定义后初始化
                         int a10[2][2];
                        a10[0][0]= 133;
                        a10[1][0]= 12;

      3、数组的访问越界的问题

                   访问了不能访问的元素
                   如果二维数组int a[m][n],下标: a[0][0] ~ a[m-1][n-1],除此之外,访问其他的元素都是越界
                  特别注意: 数组的越界在我们的C99编译器下,不报错,也能执行。只不过获取的数据不是我们想要的

      4、数组的访问

                  数组名[第一维下标][第二维下标]

      5、数组的存储细节

                 不管是一维数组还是二维数组,在内存中存储都是连续的
                   对于二维数组来说,逐行存储。
                                     int a[2][2];
                          数组的首地值 = a = a[0] = &a[0][0]
                         二维数组的占用的总字节数: 2*2*4 = 16
                              sizeof(a) = 16
                         二维数组的行数: sizeof(a)/sizeof(a[1])
                         列数: sizeof(a[0])/sizeof(int)

        6、数组的遍历

                         for(int i=0;i<rows;i++){
                                for(int j=0;j<cols;j++){
                                              printf ("%d\t",a[i][j]);
                                      }
                          }

        7、数组和函数之间的关系

                  1)数组的元素作为函数的实参
                          值传递:把数组元素的值赋值给形参
                  2)数组名作为函数的实参
                         地址的传递:把数组的首地址传递给函数的形参(让函数的形参也指向了数组的这个空间)

五、字符数组

     1、概念

           字符变量可以存储字符常量 char ch = 'a';
           字符变量不可以存储字符串常量 char ch="xxx"; 错误的
           C语言可以用字符数组来存储字符串
              字符数组定义、初始化以及使用与普通数组类似。
              不同点:字符数组存储字符串
          char ch[100]={"sadfasdfasfasdfasdfasdfasdfasdf"}; //字符串在存储的时候,除了存储可见的字符还会存储一个字符串结束的标志 \0
          char ch[10]="xxxxx";

       2、字符数组的输入输出

                 %s 可以输入、输出一个字符串
                 %s 特点:遇到'\0'就结束,否则停不下来,直到遇到'\0'
                      printf("%s",s4); //bcabc
                 %s 接收键盘输入
                      char ch[10];
                      scanf("%s",ch); //输入字符串的时候不能有空格

       3、字符串处理函数

              1)puts函数       一般形式:puts(字符数组名)    作用:将一个字符串(以‘\0’结束的字符序列)输出到终端。               2)gets函数       一般形式:gets(字符数组名)    作用:从终端输入一个字符串到字符数组。               3)strcat 函数    一般形式:strcat(字符数组 1,字符数组 2)   作用:连接两个字符数组中的字符串,把字符串2接到字符串1后面,结果放到字符数组1中。               4)strcoy函数    一般形式:strcoy(字符数组 1,字符串 2)    作用:将字符串2复制到字符数组1中               5)strcmp函数  一般形式:strcmp(字符串1,字符串2)        作用:比较字符串1和字符串2。比较的规则是自左至右逐个字符比较ASCII值               6)strlen函数    一般形式:strlen(字符数组)       作用:测试字符串长度,函数值为字符串中的实际长度(不包括‘\0’)。

       4、应用举例:单词首字母大写&统计单词个数

#include <stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
char str[100];
gets(str); //接收字符保存到数组中
int word=0;
int count=0;
for(int i=0;str[i]!='\0';i++){ //for循环遍历
if(str[i]==' '){ //如果前面是空格,则下一个一定是单词
word=0;
}else if(word==0){ //如果是单词
str[i]=str[i]-32; //单词首字母大写
count++; //计数器+1
word=1; //重新赋值为不是单词的标志
}
}
printf("单词的个数:%d\n",count);
printf("%s",str);
return 0;
}

第二讲  指 针

一、指针的基本介绍

          1、基本概念   

             地址:内存是由若干个1个字节的内存单元组成的存储器计算机为了管理内存单元,给每个字节都进行编号,编号的就是地址
             指针:地址就是指针
             变量值:地址指向的内存单元值:编号对应的存储内容
             变量访问的方法:直接访问 间接访问
               1)直接访问:用变量名访问其代表的存储空间
               2)间接访问:通过内存地址访问地址所对应的存储单元的内容

         2、指针和变量之间的关系

                 指针可以间接的访问变量的值
              1)指针变量:就是用来存放地址的变量
                    指针变量也遵守变量使用的规则 :先定义 --->初始化 -->使用
              2)定义指针变量
                      数据类型* 指针变量名;
                               int *p;     //变量名 p
                     //int表示指针变量只能存放一个整型数据的地址
                    //* 特殊符号表示指针类型  int p;//普通的整型变量, int *p;//指针变量
              3)指针变量初始化
                     变量没有初始化,是有值的 //垃圾值
                     对于指针变量, int *p; //p 随机的, p 0xff1111 10
                          *p = 10; //如果不初始化直接使用,可能会导致系统崩溃
                       野指针:定义之后,没有初始化
                    (1)定义的同时进行初始化
                             int *p=NULL; //赋值为NULL ,表示谁都不指
                             int *p1 = 0; //同上
                                  int a=10;
                                  int *p2=&a;
                                  int *p3=&a;
                                  int *p4 = p2;
                                  p3 = p4; //指针的指向可以改变
                    (2)先定义,后出初始化
                               int *p;
                               p = NULL;
                               int *p1;
                               p1=&a;
                    注意:1)多个指针可以指向同一个变量
                               2)指针的指向是可以改变的
                               3) int *p; p = 100;//错误的 存放的时地址,现在给的是整数值
                               4) *p = &a;错误 //*p是整型的变量,只能赋值数值,p是地址
                               3)使用指针变量间接的访问变量值
                                                            int *p = &a;
                                     *p 就是访问p中存放的地址代表的存储空间的值,p指向的存储空间的值

        3、指针的应用场景

                 1)在被调函数中,修改主调函数的变量值
           void change(int *num)
{
*num = 10;
}
                 2)可以让函数有多个返回值
        //写个一个函数,计算两个数的和、差、乘积、商
void sumAndMinusAndJiAndShang(int num1,int num2,int *sum,int*minus,int *ji,int *shang)
{
*sum = num1 + num2;
*minus = num1 - num2;
*ji = num1 * num2;
*shang = num1 / num2;
}

        4、多级指针介绍

                  二级及以上的指针
                  一级:指针指向的是一个基本数据类型变量的地址
                  二级:指向的又是一个地址
                         int a = 10;
                         int *p = &a; //p是一级
                         int **p1 = &p; //p1 ---> p p1是二级

       5、指针变量为什么要区分类型

               前提:不同类型的指针变量在内存中占用8个字节(地址)
                  为什么都占用8个字节还要区分类型呢?
                  char *c; //c存放的时地址 *c 从c存放的地址开始 ,连续取1个字节
                  int *p; *p 从p存放的地址开始 ,连续取4个字节
                  int a=10;
                 char *c2 = &a; //从变量a的首地址开始,取了1个字节(实际4个,取少了)
                 double *d1 = &a; //从变量a的首地址开始,取了8个字节(实际4个,取多了)

二、指针与数组

        1、数组指针

             1) 指向数组元素的指针变量,就是数组指针
                     int arr[3]={1,2,3};
                     int *p = &a[0]; p指向了第一个数组元素
                     int *p1 = arr; p和p1都指向了数组的第一个元素
                    *p 得到了数组的一个元素的值 1     
                             *p1=1
                     p和p1 都是指针变量
                             p = &a[2];
                    *p 得到数组的第三个元素值

        2、指针数组:存放指针的数组

                    一维的指针数组                      int a[3];
                    int *a[3] = {int类型数据的地址1, int类型数据的地址2, int类型数据的地址3};

       3、指针运算

              1)指针变量直接+数字
                     int arr[3]={1,2,3};
                     int *p = arr;
                     p = p+1;
              2)两个指针变量相减
                    int *p = arr;
                    int *p1 = &a[2];
                    p1 - p = 2 误区,往往认为是地址的差值,其实不是,则是两个地址之间跨过的元素的个数 3

        4、二维数组指针 

              1) 用数组名访问二维数组
黑马程序员——ios开发基础之C语言数组、指针与结构体
              2) 二维数组指针的定义:                    一般形式为:
                   数据类型 (*指针变量名) [二维数组列数];
                        int arr[2][2]={1,2,3,4};
                                 p ---> a[0] 1 2
                                 p+1---> a[1] 3 4
                        int (*p)[2]; //定义二维数组指针,行指针
                        p = arr; // 给二维数组指针初始化
                      *(*(p+i)+j) 等价于 a[i][j]

三、指针与字符串

            1、字符串指针,用来保存字符串

                    char *s="agadsf"; // 有\0

            2、用字符串数组的方法

                    char ch[]="dafasdf";// 有\0

            3、 char *c = &ch;

              注意点:
                       1)字符串指针和字符指针的区别:
                            字符串指针保存的是字符串的首地址,字符指针保存的是字符变量的地址,根据赋值是否使用“”来区别是否是字符串指针
                       2)字符串指针和字符数组的的区别
                               1)区别一,能否重新赋值问题
                                       char ch[20]="xxxxx";
                                       ch = "asdfasdf"; // 不可以的 ch是常量,存储的是数组的首地址
                                       char *ss="xxxxxx"; //"xxxxxx" 0x01
                                       ss = "xxx"; // 可以的, ss是指针变量,
                                2)区别二,存储的区别
                                       char ch[10]="xxxx"; 存放的是栈区(可读可写)
                                          x x x x \0 0 0 0 0 0 0 0
                                        ch[4]='A'
                                       char *str ="abcp"; 存放的是常量去(只读)
                                              0123
                                            *str a
                                         *(str+1) = 'x';

            4、字符串数组

                        存储字符串的几种方式
                           1)二维的字符数组
                                    char name[10][20]={
                                            "fengjie",
                                            "suibian",
                                              "xxxxxx"
                                     }
                           2)用一维的指针数组存放字符串
                                    char *name[10]={
                                               "fengjie",
                                              "suibian",
                                              "xxxxxx"
                                      }

             5、应用:字符串排序

#include <stdio.h>
#include <string.h>
void print_arr(char *str[],int len){
for (int i=0; i<len; i++) {
printf("%s\n",str[i]);
}
}
/**
* 用冒泡排序法,实现对字符串数组排序
**
@param name 字符串数组
*@param len 数组长度
*/
void paixu(char *name[],int len){
for (int i=0; i<len-1; i++) {
for (int j=0; j<len-i-1; j++) {
//比较相邻的元素
if (strcmp(name[j], name[j+1])>0) { //如果前面的大于后面的,就交换
char *temp;//定义一个字符串指针临时变量
temp = name[j];
name[j] = name[j+1];
name[j+1] = temp;
}
}
}
}
void sortArray(char *str[],int len){
//选择排序法
int min;
for (int i=0; i<len-1; i++) {
min = i;
for (int j=i+1; j<len; j++) {
if (strcmp(str[j], str[min])<0) { //如果下标为j的字符串小于min,则把j赋值给min
min = j;
}
}
if (i!=min) { //如果min不等于i则把min对应的字符串和i对应的交换
char *temp;
temp = str[i];
str[i] = str[min];
str[min] = temp;
}
}
}
int main(int argc, const char * argv[]) {
char *name[]={ "CHINA","AMERICA","AUSTRALIA","FRANCE","GERMAN"};
paixu(name, 5); //调用冒泡
print_arr(name, 5);
printf("\n");
sortArray(name, 5); //调用选择
print_arr(name, 5);
return 0;
}

四、const修饰指针

                 const作用可以把变量变成只读的(常量)

            1、修饰变量

                    const int a=23;
                    a = 20; (错误的)

           2、修饰指针

                 const int *p; //p指向的变量的值不能修改,指向可以修改
                 int const *p; //同上 
                 int * const p; //值可以变,指向不能变
                const int* const p;// 指向和值都不能变

           3、技巧:

                        const 在 * 的左侧 //指向可变,值不能变
                        const 在 * 的右侧 //指向不可变 值可变
                        const 在 * 的两侧 //指向和值都不可以变

五、指针与函数

        1、指针函数   

             返回值是指针的函数
                char * getday(){ 
                  return "星期一";
                }
              int * getAddr(int *a,int *b){
                   return *a>*b?a:b;
                }

       2、函数指针

            指向函数的指针
            格式:返回值 (*指针变量名)(函数的参数);
                 int sum(int a,int b){
                     return a+b;
                 }
            //定义一个函数指针p1, p1只能指向返回值是int类型,并且函数参数有两个,而且整形
            int (*p1)(int a,int b);
            int (*p2)(int,int);

        3、应用:输出星期

#include <stdio.h>
char *getDay(int n){
char *days[]={
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六",
"星期日"
};
return (n>=1&&n<=7)?days[n-1]:"输入不合法~";
}
int main(int argc, const char * argv[]) {
int a;
char *c;
printf("请输入数字:\n");
scanf("%d",&a);
c= getDay(a);
printf("%s\n",c);
return 0;
}

第三讲  结构体

一、结构体

       1、概念     

              结构体:若干个相同或者不同类型的数据组成的新的类型
              注意:结构体只是一个类型
              定义结构体: 
                        struct 结构体名{
                                成员列表 
                              格式: 类型 变量名;
                         };

       2、结构体变量

               结构体变量特点:一个复合类型,具备结构体的特性
                   struct stu{
                        int age;
                   }stu1,stu2;
              //匿名结构体
                   struct{
                      int model;
                    }s1;
              //先定义结构体,后定义变量
               struct stu stu3;

       3、初始化结构体变量

                 初始化的时候,注意成员的顺序
               1)    struct stu{
                            int age;
                           char name[20];
                      }stu1={23,"sss"};
              2)  struct stu stu3={18,"sb"};
              3)struct stu stu4;
                    strcpy(stu4.name,"xxxx");//stu4.name="xxx";

       4、结构体的访问 

                  结构体变量.成员名
                  stu4.name 访问姓名
                  stu4.age    访问age

       5、结构体存储原理

                结构体在内存中占用的存储空间是所有元素占用空间之和(考虑对齐)
               对齐:主要方便计算机的读取,提升读取效率
               模数:结构体基本数据类型成员中在内存中占用字节数最大的那个数
              分配:分配模数的倍数
                        如果有剩余的空间,且能够存储结构体的下一个成员,不再分配新的,否则的都分配一个模数大小的空间

二、结构体数组

         1、结构体的数组

                    由相同类型的结构体变量组成的有序的集合。
                    定义格式:
               1) 定义结构体的同时定义结构体数组
                            struct Car{
                               int lunzi;
                              int speed;
                            }cars[5];
              2) 使用匿名结构体定义数组
                             struct {
                             int lunzi;
                            int speed;
                            }cars[5];
             3)先定义结构体在定义结构体数组
                     struct Car cars[5];

       2、初始化:

                       1) 定义结构体数组的同时进行初始化1
                                    struct Car{
                                       int lunzi;
                                       int speed;
                                      char name[20];
                                    }cars[2]={{2,50},{80,300}};
                      2)
                                     struct {
                                         int lunzi;
                                         int speed; 
                                      }cars[2]={{2,50},{80,300}};
                     3)
                                    struct Car cars[2]={{2,50},{80,300}};
                    4)先定义数组,后初始化
                                        cars[0].lunzi = 4;
                                       cars[0].speed = 200;
                                     //cars[0].name="xxxx"; 错误的
                                       strcpy(cars[0].name,"xxxx");
                                        const char a;
                                    //用一个整体去初始化                                  
                                   cars[1]=(struct Car){6,100};

三、结构体指针

                定义一个指针 指向 结构体变量
                   格式:结构体类型 * 结构体指针变量名;
                                struct Student stu1;
                                struct Studetn *pstu;
                                      pstu = &stu1;
                   目的:间接访问 结构体变量中保存的成员变量值
                               (*pstu).name      (*pstu).sno
                  新的访问方法
                           pstu->name 等价于 (*pstu).name

四、结构体与函数之间的关系

             1)结构体变量的成员变量值做函数参数(除了数组之外,都是值传递)
             2)结构体变量作为函数的参数 (值传递)
             3)结构体指针作为函数的参数 (地址传递)
       结构体应用举例:
//1)利用stu的结构体,计算学生平均成绩和不及格人数 
//2)打印80-100分学生的成绩及姓名
#include <stdio.h>
struct stu{
int num;
char *name;
char sex;
float score;
};
int main(int argc, const char * argv[]) {
//1、定义结构体数组
struct stu boy[5]={
{101,"Li ping",'F',45},
{102,"Zhang ping",'M',62.5},
{103,"He fang",'F',92.5},
{104,"Cheng ling",'M',87},
{105,"Wang ming",'M',58}};
float sum = 0.0f;
int count=0; //保存不及格的人数
for (int i=0; i<5; i++) {
// 计算总成绩
sum+=boy[i].score;
// 判断成绩是否小于60 ,如果小于了60 要让计算器+1
if (boy[i].score<60) {
count++;
}else if (boy[i].score>=80 && boy[i].score<=100){
// 判断是否大于80小于100
// 如果在这个区间,应该输出姓名和成绩
printf("姓名: %s,成绩:%.2f\n",boy[i].name,boy[i].score);
}
}
printf("平均值: %.2f\n",sum/5);
printf("不及格人得个数: %d\n",count);
return 0;
}

五、枚举类型

              当程序中需要给某一个变量值,限定取值范围的时候,可以使用枚举
              1)枚举类型
                           enum 枚举类型名{枚举值1,值2,值3,...};
             2)枚举类型的变量
                 enum SEX{man,women,yao}isex;
                 enum {man,women,yao}s1;
                      enum SEX s2;
            3)枚举类型变量的使用
                   A 枚举元素的值
                  枚举元素是系统默认给的,我们自己也可以修改从第一个枚举元素开始,依次给初始化值,直到结束或者遇到指定的元素值,第一个值从0                  开始,依次+1
                  B 给枚举类型变量赋值 
                        isex = man;
                       printf("%d\n",isex);

六、typedef 定义类型

                  给某一个类型取别名
                     typedef 原类型 新类型名;
                     新类型名尽量要大写
             1)给基本数据类型起别名
                      typedef int INT ;
                     INT a,b; //a b 就是Int类型的
             2)给数组其别名
                        int a[10];
                       typedef int ARRAY[3]; //ARRAY 不是数组名,而是新起得别名
                       ARRAY a1,a2; //a1和a2是两个数组,长度为3
             3) typedef 给结构体起别名
                       typedef struct student {。。。。。。。 } STU;
                       typedef struct {。。。。。。。 } FF;
                       typedef struct stduent STUDENT;
            4)给枚举类型起别名
                       typedef enum SEX {..........} ISEX;
                       typedef enum {。。。。。。。 } SEX;
                       typedef enum SEX SS;
                       typedef ISEX IIII;
           5)给函数指针起别名
                      int (*psum)(int,int); //函数指针
                     typedef int (*FUN)(int ,int ); //FUN不是一个指针,而是一个别名
                       FUN f1,f2;