初学c课程笔记整理7-->>二维数组、字符串、指针

是什么?有什么用?用在什么地方?(理解)
养成良好的编程习惯;
培养编程思想;
写代码之前应该先分析需求,分析完需求再开始写代码;(写注释)
 
1.二维数组
 
1.1 二维数组的基本概念:
 
     所谓多维数组就是一个一维数组的每个元素又被声明为一 维数组,从而构成二维数组. 可以说二维数组是特殊的一维数组。
 
  示例
      int a[2][3]
     可以看作由一维数组a[0]和一维数组a[1]组成,这两个一维数组都包含了3个int类型的元素
 
1.2 二维数组的定义:
 
     数组中的每一个元素又是一个数组, 那么这个数组就称之为二维数组
     元素类型 数组名称[一维数组的个数][每个一维数组的元素个数];
     元素类型 数组名称[行数][列数];
    
     元素类型: 说明二维数组中每个一维数组存储什么类型的数据
     一维数组的个数: 说明二维数组有多少个元素
     每个一维数组的元素个数 说明二维数组中每一个一维数组的元素个数
     */
    int scoress[3][5] =
    {
        {1, 3, 5, 7, 9}, // 0 
        {2, 4, 6, 8, 10},// 1
        {1, 2, 3, 4 , 5} // 2
    };  // 每一个一维数组都是二维数组的一个元素
 
 如何遍历二维数组
     思路: 1.取出二维数组的每一个元素(取出二维数组中的一维数组)
          2.遍历一维数组
 
1.3 二维数组的存储
存储方式:
     1)计算机会给二维数组分配一块连续的存储空间
     2)数组名代表数组的首地址,从首地址位置,依次存入第1行、第2行、.....
     3)每一行存储方式,从行首地址还是,依次存储行的第1个元素、第2个元素、第3个元素......
     4)每个元素占用相同的字节数(取决于数组类型)
     5)并且数组中元素之间的地址是连续
 
二维数组的存放顺序是按行存放的,先存放第一行的元素,再存放第2行的元素
     
1.4 二维数组初始化及注意点:
 
1.3.1二维数组的多种初始化方式
     1.定义的同时初始化
    int names[2][3] =
    {
        {'l', 'n', 'j'},
        {'x', 'm', 'g'}
    };
     2.先定义再初始化
    int names2[2][3];
    names2[0][0] = 'l';
    names2[0][1] = 'n';
    names2[0][2] = 'j';
   
    names2[1][0] = 'x';
    names2[1][1] = 'm';
    names2[1][2] = 'g';
    
     3.完全初始化
    int names3[2][3] =
    {
        {'l', 'n', 'j'},
        {'x', 'm', 'g'}
    };
   
     4.不完全初始化
    int names4[2][3] =
    {
        {'l', 'n'},
    };
   
    5.省略元素个数的两种写法
     明确的告诉二维数组, 我们有2个一维数组
    char names5[2][3] =
    {
        'l', 'n', 'j',
        'x', 'm', 'g'
    };
    char names15[2][3] =
    {
        'l', 'n', 'j',
        'x', 'm'
    };
   
     没有告诉二维数组我们有几个一维数组
     如果在"定义的同时"进行初始化, 那么一位数组的个数可以省略
    系统会自动根据每一个一维数组能够存放多少个元素, 自动根据初始化的值推断出二维数组中一共有多少个元素(多少个一维数组)
    char names6[][3] =
    {
        'l', 'n', 'j',
        'x', 'm', 'g',
        'n', 'b'
    };
   
     6.错误写法
    ⚠️ 注意点: 每个一维数组的元素个数不能省略
 
    int names7[2][] =
    {
        {'l', 'n', 'j'},
        {'x', 'm', 'g'}
    };
    
     搞不清楚应该分配多大的存储空间, 以及搞不清楚应该把哪些数据赋值给第一个数组, 以及哪些数据赋值给第二个数组
    int names7[2][] =
    {
        'l', 'n', 'j',
        'x', 'm', 'g'
    };//错误写法
    
1.5 二维数组与函数
 
 
1.二维数组的元素作为函数参数
 二维数组的元素就相当于变量,作为函数参数与变量相同 
 
2.二维数组中的一维数组作为函数
 二维数组的一维数组实际上就是一个一维数组,作为函数参数与一维数组相同
 
3.二维数组作为函数参数
  **二维数组作为函数参数是地址传递**
 二维数组作为函数形参,参数中一维数组的元素个数不可以省略
void test(char cs[2][]) // 错误写法
{
    printf("我被执行了\n");
}
 
void test(char cs[2][3]) // 正确写法
{
    printf("我被执行了\n");
}
 
void test(char cs[][3]) // 正确写法
{
    printf("我被执行了\n");
  二维数组作为函数参数,在被调函数中不能获得其有多少行,需要通过参数传入。
```
void test(char cs[2][3])
{
    int row = sizeof(cs);
    printf("row = %zu\n", row);
}
输出结果:
row = 8
```
 
- 二维数组作为函数参数,在被调函数中可以计算出二维数组有多少列
 
```
void test(char cs[2][3])
{
    size_t col = sizeof(cs[0]);
    printf("col = %zd\n", col);
}
输出结果:
col = 3
```
 以后只要看到函数的参数是一个数组, 那么就是地址传递
 在函数中修改形参的值会影响到参数
 
2.字符串
 
1.字符串概念
 
      字符串是位于双引号中的字符序列
      在内存中以“\0”结束,所占字节比实际多一个
 
2.字符串的初始化
 
- 在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串。前面介绍字符串常量时,已说明字符串总是以‘\0’作为串的结束符。因此当把一个字符串存入一个数组时,也把结束符‘\0’存入数组,并以此作为该字符串是否结束的标志。有了‘\0’标志后,就不必再用字符数组 的长度来判断字符串的长度了。
 
- 初始化
```
    char name[9] = "lnj"; //在内存中以“\0”结束, \0ASCII码值是0
    char name1[9] = {'l','n','j','\0'};
    char name2[9] = {'l','n','j',0};
    char name3[9] = {'l','n','j'};//静态数组如果没有赋值默认就是0,0就相当于\0
```
- 错误的初始化方式
```
     //不正确地写法,结尾没有\0 ,只是普通的字符数组
    char name4[] = {'l','n','j'};
 
     //    \0的作用:字符串结束的标志
    char name[] = "c\0ool";
     printf("name = %s\n",name);
输出结果: c
 
3.字符串的输出、输入
     使用的格式字符串为“%s”,表示输入、输出的是一个字符串
        scant(“%s”,ch);//输入
        printf(“%s”,ch);//输出
   %s的原理, 从传入的"地址"开始逐个取出, 直到遇到"\0"位置
 
4.字符串的注意点
 字符串注意点, 字符串的初始化
    char str1[] = "lnj";
    char str2[] = {'l', 'n', 'j', '\0'};
    // 部分初始化, 部分初始化中, 没有被初始化的元素默认是0
    // \0对应的ASCII 0
    char str3[10] =  {'l', 'n', 'j'}; // l n j 0000000
   
    char str4[3] = {'l', 'n', 'j'}; // 该方式不是字符串, 而是字符数组, 因为没有\0
    char str5[] = {'l', 'n', 'j'}; // 错误写法
   
       需要明白的一点就是字符串以\0结尾, 没有\0就不是字符串
       只要是用双引号括起来的都是字符串
       字符串的本质就是数组
3.指针(重点)只能保存地址
3.1内存地址
地址与内存单元中的数据是两个完全不同的概念
    地址如同房间编号
    内存单元如同房间
    内存单元中存放着数据
 
变量地址:
     系统分配给"变量"的"内存单元"的起始地址
 
3.2 什么是指针
      在计算机中所有数据都存储在内存单元中,而每个内存单元都有一个对应的地址, 只要通过这个地址就能找到对应单元中存储的数据. 由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”
 
内存单元的指针(地址)和内存单元的内容是两个不同的概念。
 
3.3 什么是指针变量
在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是
某个内存单元的地址或称为某内存单元的指针。
    + 严格意义上说,指针是一个地址,是一个常量
    + 针变量是存放一个地址,是一个变量。
 
 示例
 
 
3.4定义指针变量的格式
 指针变量的定义包括两个内容:
     指针类型说明,即定义变量为一个指针变量;
     指针变量名;
> 其中,*表示这是一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指 向的变量的数据类型
 
char *p; // 一个用于指向字符形变量的指针
int *q; // 一个用于指向整形变量的指针
long *t; // 一个用于指向长整形变量的指针
float *r; // 一个用于指向单精度浮点形变量的指针
double *s; // 一个用于指向双精度浮点形变量的指针
 
⚠️注意
     1)在定义指针时,“*”号表示定义的变量是指针变量,变量的值只能存放地址。
     2)一个类型的指针只能指向同类型的变量,不能指向其他类型的变量。
     3)指针也可以被声明为全局、静态局部和局部的。
 
3.5指针变量初始化及注意点
 
1.指针变量的初始化方法
 指针变量初始化的方法有两种:定义的同时进行初始化和先定义后初始化
    定义的同时进行初始化
           
            int a = 5;
            int *p = &a;
 
    先定义后初始化
 
            int a = 5;
            int *p;
            p=&a;
 
     把指针初始化为NUL
 
            int *p=NULL;
            int *q=0;
 
不合法的初始化:
    指针变量不能被赋值一个整数值(因为我们不知道这个整形常量是内存哪块地址
int *p;
p =  250; // 错误写法
int *p;
*p=&a; //错误写法
int *p;
*p = &a;//正确写法
⚠️注意:
多个指针变量可以指向同一个地址
 
指针的指向是可以改变
int a = 5;
int *p = &a;
int b = 10;
p = &b; // 修改指针指
 指针没有初始化里面是一个垃圾值,这时候我们这是一个野指针
    + 野指针可能会导致程序崩溃
    + 野指针访问你不该访问数据
    + 所以指针必须初始化才可以访问其所指向存储区域
 
访问指针所指向的存储空间
int a = 5;
int *p = &a;
printf("a = %d", *p); // 访问指针变量
 
4.(多)二级指针
 
二级指针介绍
如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。也称为“二级指针”
 
 
char c = 'a';
    char *cp;
    cp = &c;
    char **cp2;
    cp2 = &cp;
    printf("c = %c", **cp2);
 
多级指针介绍
int ***m1; 取值***m1
int *****m2 取值*****m2
 
 
posted @ 2015-10-23 00:03  a滴答  阅读(294)  评论(0编辑  收藏  举报