C语言学习day4

目录

一.数组

        1.1数组概念

        1.2一维数组

                1.2.1一维数组定义           

                1.2.2一维数组内存的分配    

                1.2.3一维数组的使用

                1.2.4数组元素赋值

        1.2二维数组

                1.2.1二维数组的定义

                1.2.2二维数组的使用

 二.指针

        2.1指针概念

                2.1.1指针的声明

                2.1.2指针的使用

        2.2指针与数组

                2.2.1指针与一维数组

                        2.2.2.1演示指针和一维数组

                2.2.1数组指针

                2.2.2指针数组

                2.2.3指针与二维数组

        2.3二级指针

                2.3.1二级指针简单的运算

一.数组

        1.1数组概念

        数组在内存上是连续的,它是用来存储一组类型相同的数据的,数组是一个构造类型的数据。

        1.2一维数组

                1.2.1一维数组定义           

储存类型 数据类型 数组名[i]

存储类型: auto,const,static,extern,register,volatile
没有写存储类型的变量默认是auto

数据类型: char,short,int,long,lomg long,构造类型,float,double

注意:
    1.数组名是一个常量,定义时要符合命名规范。
    2.常量是不可修改的
    3.i代表了一个常量,表示数组中有几个元素。数组下标的范围 0到i-1
    4.在使用时特别需要注意数组下标越界的问题,数组越界访问编译器不会报错
    5.数组元素必须逐个引用

例如:
    int name[5]; // 这是定义了一个一维数组,数组名为name,数组名name是这个数组的首地址,
name是一个常量不可以被修改,他的含义是这个数组中有5个int类型的数据元素
注意:数组一旦定义好了 就不能整体赋值了

                1.2.2一维数组内存的分配    

在内存中,数组占用连续的存储空间,并且根据每个元素所占存储空间的大小来进行分配内存。
使用sizeof(数组名)可以计算出数组所占空间的大小,sizeof(数组名[下标])可以计算数组中
每个元素所占存储空间的大小。

                1.2.3一维数组的使用

一维数组初始化:
    1.如果数组定义完不进行初始化,那么里面存放的是一些脏数据。
        例如:int name[5]; 定义完之后不对它进行初始化,那么name数组里面的值就是一些脏数据,随机值
    2.在定义数组是可以进行不完全初始化,不完全初始化是按照数组下标的大小顺序来进行初始化的。
        例如: int name[5]={1,2}; 这里只是对name数组下标为0,1的元素进行初始化,下标为2,3,4的元素默认使用0来进行初始化。
    3.完全初始化就是在定义数组时,对数组的每一个元素都进行了初始化。
        例如: int name[5]={1,2,3,4,5}; 这就是完全初始化
注意:
    1.若要在定义时进行初始化那么只能把数据写在定义后面。
    2.如果数组列表中的个数超出了数组元素的大小则会出错
#ifdef 1
    //正确写法
   int name[5]={1,2,3,4,5};
#endif        

#ifdef 0
    //这种初始化写法是错误的
    int name[5];
    name={1,2,3,4,5};
#endif

                1.2.4数组元素赋值

给数组元素赋值的时候可以使用数组下标赋值。
例如:
    #ifdef 1
        int main(){
            int name[3];
            name[0]=1;    //给数组下标为0的元素赋值
            name[1]=2;
            name[2]=3;
            return 0;
        }
    #endif
    //以下代码时错误的
    #ifdef 0
    int main(){
        int sum[5]={1,2,3,4,5};
        int num[5];
        sum=num;     //数组名是常量,常量不允许修改
        sum[5]=num[5]; //会出现数组下标越界
        sum[1]=num[1]; //‘=’两边取出的都是数组下标为1的元素,类型为int的常量,常量不可以被赋值
        num[5]={6,7,8,9}; //不起作用
        return 0;
    }
        
    #endif
/*     一维数组读写与遍历  */
#include<stdio.h>
int main(){
    int name[5];//定义了一个int类型,数组名为name的数组,数组中最多有五个元素,注意这里没有初始化                        
                //只是定义了一个数组。
    
                //写入数据,需要注意在访问数组时,数组下标是否越界
    for(int i=0;i<5;i++){
        printf("请输入元素");    
        scanf("%d",&name[i]);  //虽然name是数组的地址,但是name[i]代表的是第(i+1)个元素,所以需            
                               //要取地址,在接收用户输入后把值放在这个地址的内存空间
    }
    for(int i;i<5;i++){  //注意数组下标越界问题,数组下标是从0开始的,这里写(%d+1)是为了方便理解
        printf("第(%d+1)个元素为: %d\n",i,name[i]);
    }
    return 0;
}

        1.2二维数组

                1.2.1二维数组的定义

通俗来说二维数组就是有两个下标的数组。
格式定义:存储类型 数据类型 数组名 [下标1] [下标二]

说明:二维数组与一维数组类似,二维数组在内存上也是连续的

使用:int rain[5][3];//表示内含5个数组元素的数组,每个数组元素里面内含3个int类型的元素。

                1.2.2二维数组的使用

例题:
    编写一个函数,把两个数组中相对应的元素相加,然后把结果储存到第 3 个数组中。也就是说如果
数组 1中包含的值是 2、4、5、8,数组 2中包含的值是 1、0、4、6,那么该函数把 3、49、14
赋给第3 个数组。函数接受3 个数组名和一个数组大小。在一个简单的程序中测试该函数。
#include<stdio.h>
#define NUM 4
/*这一部分是函数声明,在编写函数的过程中最好每一个函数都要写上,养成良好的编程素养*/
int *array_add(int *arry_one,int *arry_two,int *result_aray,int len);
void ergodic(int *ergodic_array,int len);

int main(){
    int array_1[NUM]={1,2,3,4};
    int array_2[NUM]={1,2,3,4};
    int result[NUM];
    ergodic(array_add(array_1,array_2,result,NUM),NUM);
    return 0;
}
/*这里定义了一个指针函数,它的本质还是一个函数,只不过返回值是一个地址,后续笔记中会详细说明*/
// 1.使用函数进行数组操作,这个函数的形参需要定义成指针类型的,因为传入的参数是这个数组的地址
// 2.指针讲完数组后会详细叙述

/*  第一个参数int *arry_one  是一个int类型的指针
    第二个参数int *arry_two
    第一个参数与第二个参数里面对应元素需要相加,把得到的结果放在第三个int *result_aray参数
    所指向的内存空间里面
    第四个参数是数组的元素的个数
    */
int *array_add(int *arry_one,int *arry_two,int *result_aray,int len){
    for(int i=0;i<len;i++){
        result_aray[i]=arry_one[i]+arry_two[i];
    }
    return result_aray;
}

void ergodic(int *ergodic_array,int len){
    printf("数组元素为:");
    for(int i=0;i<len;i++){
        printf("%d ",ergodic_array[i]);

    }
    printf("\n");
}

二.指针

        2.1指针概念

什么是指针?指针就是值为内存地址的某种数据类型的变量。
例如:
    int a=10;  //a这片内存空间里存的内容是10
    int *p=&a; //p这片内存空间里存的内容是a的地址,也可以说p指向的是a
注意:
    地址运算符 :& 
    如果&后面跟一个变量的话,&取出的是这个变量的地址
    
    地址运算符: *
    如果后面跟的是指针或者地址时,*给的是存储在指针指向地址的值
*p解释:获取p指向地址上的值,按照上面的例子得出的结果是  *p==a==10 

                2.1.1指针的声明

声明指针时必须声明指针指向变量的数据类型,不同变量的类型占用的存储空间也不同,所以操作对象
的大小也不同。

格式:类型说明符 *变量名;
注意:类型说明符表明了指针所指向对象的类型

例如:
    int *p;//变量p是一个指向int类型的指针,*p是 int 类型的

                2.1.2指针的使用

#include<stdio.h>
int main(){
    int a=10;
    int *p=&a;
    printf("p指向变量a的地址:%p\n",p);
    printf("*p的值 :%d\n",*p);
    printf("指针p的大小:%ld\n",sizeof(p));

    return 0;
}
/*p的值 :10
指针p的大小:8*/
例题:写一个函数交换变量x,y的值。
#include<stdio.h>
void interchange(int *p,int *q);
int main(){

    int x=10;
    int y=2;
    interchange(&x,&y);
    printf("x=%d\n,y=%d\n",x,y);
    return 0;
}
void interchange(int *p,int *q){
    int temp=*p;   //将指针p所指向内存空间里的值赋值给temp
                   //把这个值赋给一个临时的变量temp
    *p=*q;     //  *p = *q; 将指针 p 所指向的内存地址处的值修改为指针 q 所指向的内存地址处的值        
    *q=temp;
}

        2.2指针与数组

                2.2.1指针与一维数组

    加入在函数里面我们定义了一个数组: int name[5]={0};//把数组元素都初始化为0
    那么数组名name就是这个数组的首地址,&name[0]它的含义是取第一个数组元素的首地址name==&name[0],
他们两个都是常量在程序运行期间不会发生改变,可以使用指针接收地址的值,然后使用指针修改指向内存空间的
值。前面交换两个变量的值使用的就是指针
从新定义一个int类型的数组并初始化;
    int name[5]={1,2,3,4,5};
    int *p=name;
那么:p+2==&name[2]; //地址相同
    *(p+2)==name[2]; //*(p+2)它的意思是从指针p所指向的地址向后移动2个类型说明符(这里是int)
的地址,然后检索存储在那里的值
                        2.2.2.1演示指针和一维数组
#include<stdio.h>
void getElement(int *p,int len); //说明:第一个参数需要传入的数据是地址,第二个是长度
int main(){
    int name[10]={1,2,3,4,5,6,7,8,9,10};
    //使用下标取元素
    for(int i=0;i<10;i++){
        printf(" %d ",name[i]);
    }
    printf("\n");
    //使用地址取元素
    for(int i=0;i<10;i++){

        printf(" %d ",*(name+i));//name表示的是首地址,(name+i)表示首地址向后偏移几个字节的
                                //类型说明符(这里是int,所以一次偏移4个字节),
                                //*(name+i)检索这个地址里面的值
    }
    printf("\n");
    getElement(name,10);
    return 0;
}
void getElement(int *p,int len){
    for(int i=0;i<10;i++){
        printf(" %d ",p[i]);
    }
    printf("\n");
    for(int i=0;i<10;i++){
        printf(" %d ",*(p+i));
    }
    printf("\n");
}
//从以上代码可以得出 p[i]==name[i]==*(name+i)==*(p+i)
//指针相减
#include<stdio.h>
int main(){
    int name[5]={1,5,3,4,5};
    int *p1,*p2,*p3;
    p1=name;    
/*注意:地址应该和指针类型兼容,就是说不能把一个double类型的地址赋值给int类型的指针*/
    p2=&name[3];
    //一个指针减去另一个指针
    //表示的是两个指针之间相差几个类型说明符(这里是int)的字节
    printf("pt2=%p  ptq=%p  p2-p1=%ld\n",p2,p1,p2-p1);
    return 0;
}
指针减去一个整数:
#include <stdio.h>
int main() {
    int array[5] = {1, 2, 3, 4, 5};
    int* ptr = &array[3];  // 指向数组中的第4个元素
    printf("原始指针的值:%p\n", ptr);
    int offset = 2;
    int* newPtr = ptr - offset;  // 将指针向前偏移2个单位
    printf("偏移后的指针的地值:%p\n", newPtr);
    printf("偏移后的指针指向的值:%d\n", *newPtr);
    return 0;
}
//注意数组越界问题
//使用函数遍历数组:使用函数声明void printArray(const int arr[], int size);
#include <stdio.h>
void printArray(const int arr[], int size);
int main() {
    int array[] = {1, 2, 3, 4, 5};
    int size = sizeof(array) / sizeof(array[0]);
    printArray(array, size);
    printf("%p\n",array);

    return 0;
}
/*1.第一个参数表明的是这是一个类型为const int arr[]的数组指针,
可以接收指向其他整型的指针或地址*/
void printArray(const int  arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    printf("%p\n",arr);
}

                2.2.1数组指针

本质是一个指针,指向一个二维数组,也叫做行指针。多用与将二维数组作为函数的参数传递时。
格式:数据类型  (*数组指针名)[列宽];
例如: int (*p)[4];//定义了一个列宽为4的的指针p ,p指向的元素为int

               2.2.2指针数组

本质是一个数组,数组中每个元素都是一个指针类型。
格式:数据类型  *指针数组名[下标]; 

    //定义了一个指针数组 数组名叫name2 数组中共有4个元素
	//每个元素都是一个 char * 类型的指针
    char *name2[4];
	name2[0] = "zhangsan";
	name2[1] = "lisi";
	name2[2] = "fulajimier.fulajimiluoweiqi.pujing";
	name2[3] = "zhaoliu";
	printf("%s\n", name2[0]);
	printf("%s\n", *(name2+1));
	printf("%s\n", name2[2]);
	printf("%s\n", name2[3]);

                 2.2.3指针与二维数组

在了解指针与数组的基础上来学习二维数组与指针.

#include<stdio.h>
int main(){
    int name[4][2]={{1,2},{3,4},{5,6},{7,8}}; 
    //这是一个数组指针,二维数组在使用时可以搭配数组指针使用,本质还是一个指针
    int (*p)[2]=NULL;
    //在使用指针的时候,如果在定义的时候不给他指定地址时建议赋值为NULL防止野指针。
    p=name;

        //1.name是二维数组首元素的地址,所以他的值和&name[0]的值相同。
        //又因为name[0]是第一个数组的首地址,所以他的值和首元素&name[0][0]的值相同
        
        //在指针变量前使用*(解引用操作)或者在数组名后使用[下标],得到引用对象的值
    printf("%p\n",name);//输出的是二维数组的首地址

        /*
        由于name是二维数组的首地址,又由于数组在内存空间上是连续的。
        那么sizeof(name)就是整个二维数组在内存空间所占的大小,sizeof(name[0])就是一维数组
        所在空间的大小。sizeof(name)/sizeof(name[0])就是二维数组中一维数组的个数
        */
    printf("%ld\n",sizeof(name)/sizeof(name[0]));
    //求一维数组同理
    printf("%ld\n",sizeof(name[0])/sizeof(name[0][0]));
    printf("-------1------------\n");
//以下是几种遍历方法
    for (int  i = 0; i < sizeof(name)/sizeof(name[0]); i++){
        for(int j=0;j<sizeof(name[0])/sizeof(name[0][0]);j++){
            printf(" %d ",name[i][j]);
        }
        printf("\n");
    }
     printf("-------2------------\n");
    for (int  i = 0; i < sizeof(name)/sizeof(name[0]); i++){
        for(int j=0;j<sizeof(name[0])/sizeof(name[0][0]);j++){
            printf(" %d ",p[i][j]);
        }
        printf("\n");
    }
     printf("-------3------------\n");
    for (int  i = 0; i < sizeof(name)/sizeof(name[0]); i++){
        for(int j=0;j<sizeof(name[0])/sizeof(name[0][0]);j++){
            printf(" %d ",*(*(p+i)+j));
        }
        printf("\n");
    }
    printf("-------4------------\n");
    for (int  i = 0; i < sizeof(name)/sizeof(name[0]); i++){
        for(int j=0;j<sizeof(name[0])/sizeof(name[0][0]);j++){
            printf(" %d ",*(p[i]+j));
        }
        printf("\n");
    }  
    return 0;
}

        2.3二级指针

二级指针是用来保存一级指针的地址的。
一般多用于将一级指针的地址作为函数的参数传递时。

int x = 10;//变量
int *p = &x;//一级指针
int **q = &p;//二级指针

                2.3.1二级指针简单的运算

#include<stdio.h>
int main(){
    int a=10;
    int *p=&a;
    int **q=&p;
    printf("a=%d , *p=%d, **q=%d\n",a,*p,**q);
    printf("&a=%p , p=%p , *q=%p \n",&a,p,*q);
    printf("&p=%p , q=%p\n",&p,q);
	//有了上述代码 有如下的等价关系
	// a <==> *p <==> **q
	// &a <==> p <==> *q
	// &p <==> q
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值