黑马程序员————C语言基本语法(数组、字符串、指针、其他数据类型)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

第一讲  数组

一、数组的基本概念

一个int类型的变量能保存一个人的年龄,如果想保存整个班的年龄呢?

1. 什么是数组

数组,从字面上看,就是一组数据的意思,没错,数组就是用来存储一组数据的

2. 数组的特点

  • 只能存放一种类型的数据,比如int类型的数组、float类型的数组
  • 里面存放的数据称为“元素”

二、数组的定义

1. 定义

  • 声明数组的类型
  • 声明数组的元素个数(需要多少存储空间)

2. 格式

元素类型数组名[元素个数];

 1 int ages[3]; //int 是数组的类型 ages是数组名 3 是数组元素的个数 

3.简单使用

  • 简单初始化: int ages[5] = {19, 19, 20, 21, 25}; 
  • 元素有顺序之分,每个元素都有一个唯一的下标(索引),从0开始
  • 数组元素的访问:a[i]

4.初始化

1)初始化方式

1 int a[3] = {10, 9, 6};  //数组一般的初始化方式
2 
3 int a[3] = {10,9}; // 没有赋值的数组元素默认为0
4 
5 int a[] = {11, 7, 6}; // 数组初始化的时候可以省略 元素个数
6 
7 int a[4] = {[1]=11,[0] = 7};  // 利用索引给数组初始化也是可以的

2)初始化注意点

 1      /* 这种写法是错误的
 2     int ages[5];
 3      ages = {10, 11, 12, 14};  //一般在定义数组的同时进行初始化
 4      */
 5 
 6     //下面这种写法也是错误的
 7      int ages[count] = {10, 11, 12};
 8      //如果想再定义数组的同事进行初始化,数组元素个数必须是常量,或者不写
 9 
10     //这种方式是正确的
11      int count = 5;       
12      int ages[count];
13      ages[0] = 10;
14      ages[1] = 11;
15      ages[2] = 18;

5.数组的内存存储分析

  • 数组存储空间的大小与长度有关和数组实际元素个数无关
  • 存储空间的划分(内存的分配是从高地址到低地址进行的,但一个数组内部元素又是从低到高进行的,与基本数据类型变量高位到低位的存储相反)
  • 数组名就是数组首元素的地址,也是数组的地址

6.其他使用

1) 数组元素和数组作为函数参数实例

 1 void change(int array[])// 数组作为函数参数,可以省略元素个数
 2 {
 3     //printf("array==%p
", array);
 4     
 5     array[0] = 100;
 6 }
 7 
 8 void change2(int n)
 9 {
10     n = 100;
11 }
12 
13 int main()
14 {
15     int ages[6] = {10, 11, 10, 11, 10, 11};
16     
17     //printf("ages==%p
", ages);  输出结果为100
18 // 数组作为函数参数,传递是整个数组的地址,修改函数形参数组元素的值,会影响到外面的实参数组
19     
20     change(ages);
21     
22     //change2(ages[0]);  数组元素作为参数
23     
24     printf("%d
", ages[0]);  //输出结果为 10
25     return 0;
26 }

2) 数组作为参数所占用内存空间(sizeof)与数组元素的遍历

 1 int maxOfArray(int array[], int length)
 2 {
 3     // 数组当做函数参数传递时,会当做指针变量来使用,指针变量在64bit编译器环境下,占据8个字节
 4     
 5     //int size = sizeof(array);
 6     //printf("array=%d
", size);  输出结果为 8
 7     
 8     
 9     // 1.定义一个变量存储最大值(默认就是首元素)
10     int max = array[0];
11     
12     // 2.遍历所有元素,找出最大值
13     for (int i = 1; i<length; i++)
14     {
15         // 如果当前元素大于max,就用当前元素覆盖max
16         if (array[i] > max)
17         {
18             max = array[i];
19         }
20     }
21     
22     return max;
23 }
24 
25 int main()
26 {
27     int ages[] = {11, 90, 67, 150, 78, 60, 70, 89, 100};
28      
29     //int size = sizeof(ages);
30     
31     //printf("ages=%d
", size);
32     int max = maxOfArray(ages, sizeof(ages)/sizeof(int));
33     
34     printf("%d
", max);  // 结果为 150
35     return 0;
36 }

第二讲  字符串

1.什么是字符串

  • 简单的字符串”itcast”
  • 一个’i’是一个字符
  • 很多个字符组合在一起就是字符串了

2.字符串的初始化

1      //字符串一般以结尾 下面 都是字符串
2     char name[8] = "it";   //"it" 其实由'i','t',''组成
3     char name2[8] = {'i', 't', ''};
4     char name3[8] = {'i', 't', 0};
5     char name4[8] = {'i', 't'};
6     
7     // 下面这个不算是一个字符串(只能说是一个字符数组)
8     char name5[] = {'i', 't'};

3. 的作用

 1 /*
 2  的作用
 3  1.字符串结束的标记
 4  2.printf("%s", name2); 
 5  会从name2这个地址开始输出字符,直到遇到为止
 6  */
 7 
 8 int main()
 9 {
10     char name[] = "itcast";
11     
12     char name2[] = {'o', 'k'};
13     
14     // printf("%s
", name); 输出结果是it
15 
16     //printf("%s
", name2);  输出的结果是 okitc
17     
18     printf("%s
", &name2[1]); //输出结果是 ktic
19     
20     return 0;
21 }

3.常用字符串处理函数(strlen)

 strlen函数:计算字符串长度

  • 计算的是字符数,并不是字数。一个汉字算作3个字符
  • 计算的字符不包括
  • 从某个地址开始数字符的个数,直到遇到为止
  • strlen函数声明在string.h文件中
 1 int main()
 2 {
 3     //int size = strlen("哈haha");
 4 
 5     //printf("%d
", size);   输出结果为7
 6     /*
 7     char name[] = "itcast";
 8     char name2[] = {'0', '', '6'};
 9     
10     int size = strlen(name2);
11     
12     printf("%d
", size);  输出结果为 7
13     */
14     
15     char name[] = "itcast";
16     
17     //printf("%s
", name);  输出结果是itcast
18     
19     printf("%c
", name[3]); // 输出结果为字符  a
20     
21     
22     return 0;
23 }

第三讲  指针

一、指针前奏

1.指针的重要性

指针是C语言中非常重要的数据类型,如果你说C语言中除了指针,其他你都学得很好,那你干脆说没学过C语言。

2.小需求

  • void change(int  n)函数调用完毕后,改变实参的值
  • 分析:修改实参的值->找到存储空间->地址

 

二、指针变量的定义

1.定义的格式

类名标识符  *指针变量名;

  int *p;// 定义了一个指针变量p 

  • 指针变量只能存储地址
  • 指针就一个作用:能够根据一个地址值,访问对应的存储空间
  • 指针变量p前面的int:指针变量p只能指向int类型的数据

2.先定义后赋值

 1     //简单取值
 2 
 3     int a = 10;
 4 
 5     int *p;
 6 
 7     p = &a;
 8 
 9     printf(“%d”, *p);
10 
11    // 简单改值
12 
13     *p = 9;

3.定义的同时赋值

int a = 10;
//定义变量a
int *p = &a;
//定义指针变量p的同时把 a地址复制给 p

4. 实现修改实参

 1 int main()
 2 {
 3 
 4     int a = 90;
 5     
 6     change(&a);
 7     
 8     printf("a=%d
", a);  //输出结果为 10
 9     
10     return 0;
11 }
12 
13 void change(int *n)
14 {
15     *n = 10;
16 }

5.注意点

 1 int main()
 2 {
 3     /* 不建议的写法, int *p只能指向int类型的数据
 4     int *p;
 5     double d = 10.0;
 6     p = &d;*/
 7     
 8     /* 指针变量只能存储地址
 9     int *p;
10     p = 200;
11     */
12     
13     /* 指针变量未经过初始化,不要拿来间接访问其他存储空间
14     int *p;
15     printf("%d
", *p);
16     */
17     
18     int a = 10;
19     /*
20     int a;
21     a = 10;
22     */
23     
24     /*
25     int *p;
26     p = &a;
27     */
28     // 定义变量时的*仅仅是一个象征,没有其他特殊含义
29     int *p = &a;
30     
31     // 不正确的写法
32     // *p = &a;
33     p = &a;
34     
35     // 这个时候的*的作用:访问指向变量p指向的存储空间
36     *p = 20;
37     
38     return 0;
39 }

三、指针探究

指针变量所占用的存储空间

 1 void test()
 2 {
 3     char c; // 1
 4     int a; // 4
 5     long b; // 8
 6     
 7     char *cp;
 8     int *ap;
 9     long *bp;
10     
11     printf("cp=%zd, ap=%zd, bp=%zd
",
12            sizeof(cp), //  cp输出结果为8
13            sizeof(ap), //ap 输出结果为8
14            sizeof(bp)); // bp输出结果为 8
15        //任何指针都占用8个字节的存储空间
16 }

为何指针变量要分类型

1 int main()
2 {
3     int a = 10 ;
4     char b = 'A';
5     int * p ;
6     p = &b ;
7     printf("%d",*p);   //输出的结果为 2625并不是 65,指针类型的作用是从指定的地址取一定字节的数据 ,*p 取的是 4个字节,取一个字节结果就为65
8     return 0 ;
9 }

四、指针与数组

1.指向一维数组元素的指针

 1     int ages[5] = {10, 9, 8, 67, 56};
 2     
 3     int *p;
 4     // 指针变量p指向了数组的首元素
 5     p = &ages[0];
 6     // 数组名就是数组的地址,也是数组首元素的地址
 7     //p = ages;
 8     
 9     /*
10      p ---> &ages[0]
11      p + 1 ---> &ages[1]
12      p + 2 ---> &ages[2]
13      p + i ---> &ages[i]
14      */
15     
16     //printf("%d
",  *(p+2));  //指针可以通过以下这两种方式访问数组元素
17     
18     printf("%d
",  p[2]);  //输出的结果为 8
 1 void change(int array[]); 
 2 
 3 int main()
 4 {
 5     // 20个字节
 6     int ages[5] = {10, 11, 19, 78, 67};
 7     
 8     change(ages);
 9     
10     return 0;
11 }
12 
13 // 利用一个指针来接收一个数组,指针变量array指向了数组的首元素
14 void change(int *array)
15 {
16     printf("%d
", array[2]);  // 输出结果为 19
17     //printf("%d
", *(array+2));
18 }
19 
20 
21 /* 以数组作为参数,其实就是一指针方式传递参数
22 void change(int array[])
23 {
24     int s = sizeof(array);
25     
26     printf("%d
", s);   //占8个字节
27 }*/

2.用指针遍历一维数组元素

 1   int ages[5] = {10, 9, 8, 67, 56};
 2     
 3     int *p;
 4     // 指针变量p指向了数组的首元素
 5     p = &ages[0];
 6     // 数组名就是数组的地址,也是数组首元素的地址
 7     //p = ages;
 8     /*
 9      for (int i = 0; i<5; i++) {
10      printf("ages[%d] = %d
", i, *(p+i));
11     //  printf("ages[%d] = %d
", i, p+i);
12      }*/
13     

五、指针与字符串

1、定义字符串

 1  // 字符串变量 字符可以修改
 2     char name[] = "it";
 3     name[0] = 'T';
 4       //printf("%s
", name); 输出结果为 Tt
 5      
 6      // 字符串常量 变量不可以修改
 7     char *name2 = "it";
 8     // 指针变量name2指向了字符串的首字符
 9     
10 
11     

2、定义字符串数组

 1 // 定义字符串数组
 2 void test2()
 3 {
 4     char *name = "jack";
 5     
 6     
 7     // 指针数组(字符串数组)
 8     char *names[5] = {"jack", "rose", "jake"};
 9     
10     // 二维字符数组(字符串数组)
11     char names2[2][10] = {"jack", "rose"};
12 }

六、指针类型的函数与指向函数的指针

1、指针类型的函数

 1 char *test();
 2 
 3 int main()
 4 {
 5     char *name = test();  //定义一个指针来接受函数的返回值
 6     
 7     printf("name=%s
", name);  //输出结果为 rose
 8     
 9     return 0;
10 }
11 
12 char *test()  //函数的返回类型是指针
13 {
14     return "rose";
15 }

2、指向函数的指针

1) 定义

 返回值类型 (*指针变量)(参数1,参数2 .......);

1      double (*p)(double, char *, int);   
2     //定义一个指向函数的指针 
3     p = haha; 
4     // 把 haha函数地址赋值给 指针p,函数名就是函数的地址 

2) 利用指针间接调用函数

void test()
{
    printf("调用了test函数
");
}

int main()
{
    // (*p)是固定写法,代表指针变量p将来肯定是指向函数
    // 左边的void:指针变量p指向的函数没有返回值
    // 右边的():指针变量p指向的函数没有形参
    void (*p)();
    
    // 指针变量p指向了test函数
    p = test;
    
     p();
    //(*p)(); // 利用指针变量间接调用函数
    
    //test(); // 直接调用函数
}

第四讲  其他数据类型

一、结构体

1、什么是结构体

当一个整体由多个数据构成时,我们可以用数组来表示这个整体,但是数组有个特点:内部的每一个元素都必须是相同类型的数据。

* 在实际应用中,我们通常需要由不同类型的数据来构成一个整体,比如学生这个整体可以由姓名、年龄、身高等数据构成,这些数据都具有不同的类型,姓名可以是字符串类型,年龄可以是整型,身高可以是浮点型。

* 为此,C语言专门提供了一种构造类型来解决上述问题,这就是结构体,它允许内部的元素是不同类型的。

2、结构体类型的定义

1) 定义结构体的类型

 struct 结构体名{

         类型名1 成员名1;

         类型名2 成员名2;

         ........

         类型名n 成员名n

};

1      struct Person  //定义结构体类型
2     { 
3        // 里面的3个变量,可以称为是结构体的成员或者属性
4         int age; // 年龄
5         double height; // 身高
6         char *name; // 姓名
7     };

3、定义结构体变量

 1      /*定义结构体变量的3种方式  */
 2  1> 先定义类型,再定义变量(分开定义)
 3  struct Student
 4  {
 5     int age;
 6  };
 7  struct Student stu;
 8  
 9  2> 定义类型的同时定义变量
10  struct Student
11  {
12     int age;
13  } stu;
14  struct Student stu2;
15  
16  3> 定义类型的同时定义变量(省略了类型名称)
17  struct
18  {
19     int age;
20  } stu;    
21  */
22 
23 /*结构体类型不能重复定义    
24      struct Student
25      {
26      int age;
27      };
28      
29      struct Student
30      {
31      double height;
32      };
33      
34      struct Student stu;     */
35  

4、结构体变量初始化

1  //第一种初始化方式 
2 struct Person p = {20, 1.55, "jack"};
3   p.age = 30;   //可以通过这种方式来修改成员的值
4   p.name = "rose";
5 // 第二种出事化方式  
6  struct Person p2 = {.height = 1.78, .name="jim", .age=30};

5、结构体的内存存储

结构体所占用的存储空间 必须是 最大成员字节数的倍数

void test()
{
    // 1.定义结构体类型(并不会分配存储空间)
    struct Student
    {
        int age;// 4个字节
        
        char a;
        
        //char *name; // 8个字节
    };
    
     // 2.定义结构体变量(真正分配存储空间)
    struct Student stu;
    //stu.age = 20;
    //stu.name = "jack";
    // 补齐算法(对齐算法)
    // 结构体所占用的存储空间 必须是 最大成员字节数的倍数
    
    int s = sizeof(stu);   
    printf("%d
", s);    //输出的结果为8
}

6、结构体数组

1)结构数组的定义及初始化

 //定义结构体类型 
  struct RankRecord
    {
        int no; // 序号  4
        int score; // 积分 4
        char *name; // 名称 8
    };   

    //定义结构体数组
      struct RankRecord records[3] =
    {
        {1, "jack", 5000},
        
        {2, "jim", 500},
        
        {3, "jake",300}
    };
    
     // 下面这种初始化方式是错误的
     //records[0] = {4, "rose", 9000};

2) 遍历结构体数组

1  for (int i = 0; i<3; i++)
2     {
3         printf("%d	%s	%d
", records[i].no, records[i].name,records[i].score);
4     }

7、指向结构体的指针

每个结构体变量都有自己的存储空间和地址,因此指针也可以指向结构体变量

* 结构体指针变量的定义形式:struct 结构体名称 *指针变量名

* 有了指向结构体的指针,那么就有3种访问结构体成员的方式

  • 结构体变量名.成员名
  • (*指针变量名).成员名
  • 指针变量名->成员名
 1 int main()
 2 {
 3     struct Student
 4     {
 5         int no;
 6         int age;
 7     };
 8     // 结构体变量
 9     struct Student stu = {1, 20};
10     
11     // 指针变量p将来指向struct Student类型的数据
12     struct Student *p;
13     
14     // 指针变量p指向了stu变量
15     p = &stu;
16     
17     p->age = 30;
18     
19     // 第一种方式
20     printf("age=%d, no=%d
", stu.age, stu.no);
21     
22     // 第二种方式
23     printf("age=%d, no=%d
", (*p).age, (*p).no);
24     
25     // 第三种方式
26     printf("age=%d, no=%d
", p->age, p->no);
27     
28     
29     return 0;
30 }

8、结构体和函数

如果结构体作为函数参数,只是将实参结构体所有成员的值对应地赋值给了形参结构体的所有成员
修改函数内部结构体的成员不会影响外面的实参结构体

 1 void test(struct Student s)
 2 {
 3     s.age = 30;
 4     s.no = 2;
 5 }
 6 
 7 // 会影响外面的实参结构体
 8 void test2(struct Student *p)
 9 {
10     p->age = 15;
11     p->no = 2;
12 
13 }
14 
15 int main()
16 {
17     struct Student stu = {28, 1};
18     
19     //test(stu);   // 成员值不变age =28,no=1
20     test2(&stu);  //成员值改变age=15, no=2
21 
22     
23     printf("age=%d, no=%d
", stu.age, stu.no);
24     
25     return 0;
26 }

9、结构体嵌套定义

1)定义

 struct 结构体名1{

         类型名1 成员名1;

         类型名2 成员名2;

         ........

         类型名n 成员名n

};

 struct 结构体名2{

         类型名1 成员名1;

         struct 结构体名1 成员名2;

         ........

         类型名n 成员名n

};

2)简单使用

 1 int main()
 2 {
 3     struct Date   //先定义一个Date  结构体类型
 4     {
 5         int year;
 6         int month;
 7         int day;
 8     };
 9     
10     
11     // 类型
12     struct Student
13     {
14         int no; // 学号
15         
16         struct Date birthday; // 生日
17         
18         struct Date ruxueDate; // 入学日期
19         
20         // 这种写法是错误的,不能自己调用自己
21         //struct Student stu;  
22     };
23     
24     
25     struct Student stu = {1, {2000, 9, 10}, {2012, 9, 10}};
26     
27     printf("year=%d,month=%d,day=%d
", stu.birthday.year, stu.birthday.month, stu.birthday.day);
28     
29     
30     
31     
32     
33     return 0;
34 }

二、枚举

1、枚举的概念

枚举是C语言中的一种基本数据类型,并不是构造类型,它可以用于声明一组常数。当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型。比如,你可以用一个枚举类型的变量来表示季节,因为季节只有4种可能的取值:春天、夏天、秋天、冬天。

2、枚举的定义

一般格式为:

  enum 枚举名 {

  枚举元素1,

  枚举元素2,

  ……

  };

    enum Sex { Man, Woman, Unkown}; 

3、枚举变量的定义

enum Sex s = Unkown;

4、枚举类型实用注意

C语言编译器会将枚举元素(Man、Woman等)作为整型常量处理,称为枚举常量。

  • 枚举元素的值取决于定义时各枚举元素排列的先后顺序。默认情况下,第一个枚举元素的值为0,第二个为1,依次顺序加1。
enum Sex { Man, Woman, Unkown};

也就是说Man的值为0,Woman的值为1,Unkown的值为2

  • 也可以在定义枚举类型时改变枚举元素的值
enum Sex { Man, Woman=2, Unkown};

没有指定值的枚举元素,其值为前一元素加1。也就说Man的值为0,Woman的值为2,Unkown的值为3

5、枚举赋值

    enum Sex { Man, Woman, Unkown};

    enum Sex s = Unkown;  //等价于s=2
    
    enum Sex s = 0;  //等价于s=Man

6、枚举的遍历

enum Sex { Man, Woman, Unkown} s;
// 遍历枚举元素
for (s = spring; s <= Unkown; s++) {
    printf("枚举元素:%d 
", s);
}
原文地址:https://www.cnblogs.com/zhaoyutang/p/4510931.html