c语言指针与数组的深入理解

简介: c语言指针与数组一: 指针的理解与操作1:指针与指针变量?指针是什么?以及指针地址的概念?指针就是地址,地址就是指针。指针变量可用于存放地址。在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。

c语言指针与数组


一: 指针的理解与操作


1:指针与指针变量?

指针是什么?以及指针地址的概念?


指针就是地址,地址就是指针。指针变量可用于存放地址。


在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。

 存放地址的变量称为指针变量。指针变量是一种特殊的变量,它不同于一般的变量,一般变量存放的是数据本身,而指针变量存放的是数据的地址。


将指针的等同于指针变量是不严格的说法,指针并不是存放地址,指针变量才可以存放地址。我们从概念上区分。但是可能会通常会把指针变量也简化称之为指针了,但是我们需要知道,实际上并不等同。

然后我们简单写代码也可以验证这个说法


#include<stdio.h>
#include<windows.h>
int main()
{
    int a = 0;
    int *p = &a;//定义了指针变量存放了a的地址
    printf("the address of a is %d\n",&a);
    printf("the value of p is %d or %p\n",p);
    system("pause");
}



2:二级指针,多级指针,指向指针的指针?


这边的指针大家在代码中就理解为指针变量就可,这样严格一些就不会弄混。

我们定义一个指针变量,既然是一个变量,那肯定需要空间,或者叫内存空间,既然是占用了内存空间,那必然会有地址,既然是有地址,我们必然可以定义另一个指针来存放该指针变量的地址。所以可以称之为双重指针。

下面展示一些 内联代码片。


#include<stdio.h>
#include<windows.h>
int main() 
{
        //指向指针的指针
        int *p1 = NULL;
        int a1 = 6;
        p1 = &a1;
        int **p2 = &p1;
        printf("the value of address of a is %d\n",&a1);
        printf("the value of p1 is %d\n",p1);
        printf("the address of p1 is %d\n",&p1);
        printf("the value of p2 is :%d\n",p2);
        printf("the value of *p2 is :%d\n",*p2);
        printf("the value of **p2 is %d\n",**p2);
        printf("the value of address of p2 is %d\n",&p2);
        system("pause");
}



指针占用空间?难道会同指向的类型变量的大小一直一致吗?

当然不是啦!


加一些代码,分别定义两个指针,一个指向charl类型,一个指向int类型,下面输出两者各占的字节数。


3:定义指针的*号与后面引用p取的 *号一样吗?

不一样啊!


int *p 这边的 *号是作为了区分指针与一般变量的符号,定义这边只说明了该变量是指针。而你在后面所用到的 *p我们可以认为是取该指针指向地址处得值得含义。上边的代码也有说明打印。所以这个也算作是一个容易混淆的区分点。


下面展示一些 内联代码片。


#include<stdio.h>
#include<windows.h>
int main() 
{
        //指向指针的指针
        char a ='c';
        char *p =&a;
        int *p1 = NULL;
        int a1 = 6;
        p1 = &a1;
        int **p2 = &p1;
        printf("the value of address of a is %d\n",&a1);
        printf("the value of p1 is %d\n",p1);
        printf("the address of p1 is %d\n",&p1);
        printf("the value of p2 is :%d\n",p2);
        printf("the value of *p2 is :%d\n",*p2);
        printf("the value of **p2 is %d\n",**p2);
        printf("the value of address of p2 is %d\n",&p2);
        printf("the size of a is %d\n",sizeof(a));
        printf("the size of a1 id %d\n",sizeof(a1));
        printf("the size of p is %d\n",sizeof(p));
        printf("the size of p1 is %d\n",sizeof(p1));
        system("pause");
}



可以看到两个指针都占四个字节,虽然指向不同的类型。所以说指针所占的内存数和指向的数据类型是没有关系的。


二: 数组理解与操作

1:定义初始化

普通的一维数组也就没什么太大的区别了,要说区别话,也可能只是类型的问题。


(1)初始化一维数组

一写可以尝试的初始化,这里就举例数值型和字符型


#include<stdio.h>
#include<windows.h>
int main()
{
    int a[] = {};
    int a1[] = {1,2,3,4};
    int a2[5] = {};
    int a3[5] = {1,2,3,4,5};
    char s1[] = {"Hello Everyone"};
    char s2[] = {'a','b','c','\0'};
    char s3[10] = {'a','b','\0'};
    char s4[10] = {"Hello "};
    //printf("%d",a[0]);
    system("pause");
}


(2)初始化二维数组

我们还是以数值型和字符型举例


#include<stdio.h>
#include<windows.h>>
int main()
{
    int array[3][4] = 
    {
        {0,1,2,3},
        {4,5,6,7},
        {8,9,10,11}
    };
    int array1[][4] = 
    {
        {1,2,3,4},
        {5,6,7,8},
        {9,10,11,12},
        {13,14,15,16},
        {17,18,19,20}
    };
    int array2[][5] = 
    {
    };
    system("pause");
    char words[][4] =
    {
       {'a','b','c','\0'},
       {'d','e','f','\0'}
    };
    char words_1[][6] =
    {
        "boy","hello","yes","right","what"
    };
    char words_2[][4] = 
    {
    };
    char words_3[3][4] =
    {
        {'a','b','c','\0'},
        {'e','f','g','\0'},
        {'i','j','k','\0'}
    };
}


2:给数组赋值

谈到给数组赋值,在一些老版本说明中,比如一维数组是必须要有常量来规定初始化的数组的大小的,就算是二维数组也要至少指定列。但是c语言版本c99后好像是可以动态赋值了,意思是你可以定义一个n,然后int[n],n需要输入即可,但是在我的版本里面这是万万不行的。


1:给整形数组赋值

我们还是按照常规的方法给数组赋值,举一个给整型二维数组赋值的例子。


#include<stdio.h>
#include<windows.h>
int main() 
{
    int arr[3][4] = {0};
    for(int i =0;i<3;i++){
        for(int j =0;j<4;j++){
            scanf("%d",&arr[i][j]);
        }
    }
      for(int i =0;i<3;i++){
        for(int j =0;j<4;j++){
           printf("%d,",arr[i][j]);
        }
    }
    system("pause");
}



赋值的时候一定要记得记得取地址,&,不加这个符号意味着你要改变地址,这怎么能让你随便改呢?


2:给字符型数组进行赋值

当然也可以通过函数赋值,也可以手动介入。


#include<stdio.h>
#include<windows.h>
int main() 
{
    // int arr[3][4] = {0};
    // for(int i =0;i<3;i++){
    //     for(int j =0;j<4;j++){
    //         scanf("%d",&arr[i][j]);
    //     }
    // }
    //   for(int i =0;i<3;i++){
    //     for(int j =0;j<4;j++){
    //        printf("%d,",arr[i][j]);
    //     }
    // }
    char name[10];
    scanf("%s",name);
    printf("the value is:[%s]",name);
    system("pause");
}



这个是空格结束的

但是可以呢,如果输入的大于定义的长度呢?你看竟然也输出来了。???



还可以通过gets()函数


#include<stdio.h>
#include<windows.h>
int main() 
{
    char name[10];
    gets(name);
    printf("the value of name is %s",name);
    system("pause");
}




fgets()函数,这个也是赋值


#include<stdio.h>
#include<windows.h>
int main() 
{
    char name[10];
   //name 字符串 ,10 长度, stdin默认输入设备
    fgets(name,10,stdin);
    printf("the value of name is %s ",name);
    system("pause");
}



当然还有其它的赋值方法,就不再举例了。

当然二维字符数组也可以赋值,道理是一样的,举例一个比较简单的赋值方法,你比如。


#include<stdio.h>
#include<windows.h>
int main() 
{
    char str[3][20];
       strcpy(str[0],"abcccc")
       strcpy(str[1],"asnksnaks");
       strcpy(str[2],"shdjkhdkjdk");
    printf("%s\n",str[0]);
    system("pause");
}


这个还是很简单的。当然你也可以使用for循环进行赋值



那么举例一个使用for循环给二维数组赋值


#include<stdio.h>
#include<windows.h>
int main() 
{
    char str[3][20];
    //    strcpy(str[0],"abcccc");//或者用sprintf(str[0],"123");
    //    strcpy(str[1],"asnksnaks");//或者用sprintf(str[1],"456");
    //    strcpy(str[2],"shdjkhdkjdk");
    // printf("%s\n",str[0]);
    // system("pause");
    for(int i =0;i<3;i++){
        scanf("%s",&str[i]);
    }
    printf("%s",str[0]);
    system("pause");
}



2:一维数组?二维数组?三维数组?


一维数组的化我们按照抽象出来的理解就是按照线性存储的方式罢了,二维的化也就是矩形,三维的化抽象出来也就是下面的这张图

什么?还有三维数组?



对啊,还有思维数组。不过只是未来理解,我们就讲到三维。

定义什么的就不需要赘述

其实你看啊,所谓的一维二维三维等等,只不过是抽象出来的概念。在内存中其实还是线性存放的。

就比如这样,下面一个二维数组。实际的存放方式是这样的。但是可能将其抽象化为矩形也是比较形象,不过我觉得,如果知道是线性的实际存放,在后面学习指针理解的化还是很有帮助的。



所以无论是多少维的数组,其在内存中的本质还是线性存放。


三: 指针与数组的复杂纠葛

1:指针与数组

指针可以配合数组干点什么事情呢?

我们定义的指针变量可以存放地址,那就可以存放数组的地址啊!


(1)指向一维数组

一个简单的运用


#include<stdio.h>
#include<windows.h>
int main()
{   
    char str[] = "I love you";
    char *target = str;
    int count = 0;
    while (*target++ !='\0')
    {   
        count++;
        /* code */
       // printf("%d",count);
    }
    printf("the total is :%d",count);
    system("pause");
}


就拿这一个说明


我们这边的target指针是指向数组的,明白了说也就是数组的首地址,就是字符I的首地址,初始化是这样,当我们给指针进行++的时候就会依次指向第二个以至于往后。取*号就是取地址处的值,ok,说明白了。


根本还有要理解指针是怎样指向的,以及怎样指向数组,这样就不会被反复套娃。


(2)指向二维数组

你看指向二维数组,我们这边形象化一下,你再理解一下数组名代表了什么?



打印输出数组名就会得到数组的首地址,也就是第一个元素的值。


要想搞清楚,那就打印验证


#include<stdio.h>
#include<windows.h>
int main(){
    int array[2][3] = {0};
    for(int i =0;i<2;i++){
        for(int j=0;j<3;j++){
            scanf("%d",&array[i][j]);
        }
    }
    printf("size of int is %d\n",sizeof(int));
    printf("the add of array pointed is %d\n",array);//我们这边按照十进制将地址打印出来,是整个数组的首地址
    printf("the value of *array pointed is %d\n",*array);//可以认为取到嵌套的一维数组的地址
    printf("the value of **array is %d\n",**array);//可以认为取到存放一维数组的值
    printf("the value of *(array+1) pointed is %d\n",*(array+1));
    printf("the add of array+1 pointed is %d\n",array+1);
    system("pause");
    /*
    输出打印后通过分析可得,array是指向五个包含元素的数组的指针
    */
}
/*
如何理解二维数组呢?二维数组根本还是在内存中按照一维数组存放的。可以认为是嵌套。
*/



写不动了,就不再举例了。我们来看搞脑子的有趣的知识点。


2:指针数组


你可能不怎么用,我承认对大一的同学们可能就离谱。什么?还有这玩意?


必要的时候没图就理解不了啊!小甲鱼的图图,我带来了。



为什么这就是一个指针数组呢?而不是数组指针?


[]的优先级别高于*,所以先结合p后结合*。


指针数组是一个数组,每个数组元素存放一个指针变量


可以干啥?可以这样做

#include<stdio.h>
#include<windows.h>
int main()
{   //下面这个是指针数组
    char *p1[5] = {
        "every one can dream!",
        "i think i can successful",
        "dont care it ,just do it for your dream",
        "how are you",
        "believe yourself"
};
    for (int i =0;i<5;i++){
        printf("%s\n",p1[i]);
    }
    system("pause");
}



你可能产生一种不可理解的意识,那就是字符串怎么能赋值给指针呢。但是并不是这个意思。

我们这样理解,声明了一个字符指针后,并用字符串常量的第一个字符的地址赋值给指针变量p1[i]。


3:数组指针


继续套娃


那么数组指针是什么?



可以看到p和*加了括号,所以会优先结合


数组指针就是指向数组的指针


来一段简单的代码


//下面演示数组指针,指向数组的指针,不要认为其指向地址,而是指向整个数组
#include<stdio.h>
#include<windows.h>
int main() 
{
    int temp[] ={1,2,3,4,5};
    int (*p2)[5] = &temp;
    int i;
    for(i =0;i<5;i++)
    {
        printf("%d\n",*(*p2+i));
    }
    system("pause");
}



问题来了,既然p2是指针,那么*p就·代表了取值,为什么要取 * 呢?


p2是指向整个数组,我们可以这样理解,进行一层 * 可以认为其取到数组第一个元素的首地址,再次*可认为取值。ok。


四:给你一些相关的内容以及遇到的问题

套娃

给几个代码


/*使用指针的方法将最大值保存到变量a中去,最小值保存到变量b中去*/
#include <stdio.h>
void ff(int *p1, int *p2) {//把实参的地址内容传递过去赋值的过程
  int a;//和main函数中的a不一样的
  a = *p1;//将p1地址上的值传给a;
//  printf("%d", &a);
  *p1 = *p2;
  *p2 = a;
}
int main() {
  int a, b;
  int *p_1, *p_2; //定义指针型变量指向int类型的变量
  scanf("%d %d", &a, &b);
  p_1 = &a; //将地址附值给p_1,p_2;
  p_2 = &b;
  printf("%d,%d\n", &a, &b);
  if (a < b) {
  ff(p_1, p_2);
  }
  printf("最大值为%d,最小值为%d", a, b);
  return 0;
}


#include<stdio.h>
#include<windows.h>
int main()
{   //初始化两个指针开始指向空
    int *p1 =NULL;
    int *p2 =NULL;
    int *p3 =NULL;
    int a =6,b =8,c =10;
    p1 =&a;//代表p1指针指向a的地址
    p2 =&b;
    p3 =&c;
    //你可以先打印*p1/*p2代表了什么,其实这次再取*的话,和指针定义的*不一样,代表取取指针指向地址处的内容
    // eg:
    printf("the value of a is %d\n",*p1);
    printf("the address of a is %p\n",p1);//打印地址直接就%p
    //交换值可以取值直接交换
    // eg:
    *p1 = *p2;
    printf("this time ,the value of a is %d\n",a);
    //?试试地址交换?
    p1 = p3;
    printf("the value of a is %d\n",a);//打印输出你只会发现值交换才是有效的,用指针只是指针的指向发生了改变
    printf("the value of pointer p1 is %d",*p1);
    system("pause");
}


#include<stdio.h>
#include<windows.h>
int main(){
    int array[2][3] = {0};
    for(int i =0;i<2;i++){
        for(int j=0;j<3;j++){
            scanf("%d",&array[i][j]);
        }
    }
    printf("size of int is %d\n",sizeof(int));
    printf("the add of array pointed is %d\n",array);//我们这边按照十进制将地址打印出来,是整个数组的首地址
    printf("the value of *array pointed is %d\n",*array);//可以认为取到嵌套的一维数组的地址
    printf("the value of **array is %d\n",**array);//可以认为取到存放一维数组的值
    printf("the value of *(array+1) pointed is %d\n",*(array+1));
    printf("the add of array+1 pointed is %d\n",array+1);
    system("pause");
    /*
    输出打印后通过分析可得,array是指向五个包含元素的数组的指针
    */
}
/*
如何理解二维数组呢?二维数组根本还是在内存中按照一维数组存放的。可以认为是嵌套。
*/


#include<stdio.h>
#include<windows.h>
//指针数组
int main()
{
    char *cBooks[] = 
    {
        "Cease to struggle and you cease to live",
        "Time ca heal a broken heart,but it can also break a waiting heart",
        "the fox changes his skin but not his habbits",
        "Time is but a river flowing from our past"
    };
    char **jgdabc;
    char **jgdabc_loves[4];
    jgdabc_loves[0] = &cBooks[0];
    jgdabc_loves[1]  = &cBooks[1];
    jgdabc_loves[2] = &cBooks[2];
    jgdabc_loves[3] = &cBooks[3];
    printf("%d\n",jgdabc_loves[0]);
    printf("%d\n",*jgdabc_loves);
    printf("%s\n",*jgdabc_loves[0]);
    printf("%c\n",**jgdabc_loves[0]);
    printf("%c\n",**jgdabc_loves[1]);
    system("pause");
}


这边请自行运行并思考,专注指针的要点,以及指向指针的·指针的含义。

目录
打赏
0
0
0
0
0
分享
相关文章
一文彻底搞明白C语言的数组
本文详细介绍了C语言中的数组,包括定义、初始化(静态与动态)、存储方式、访问方法及常用操作,如遍历、修改元素和作为函数参数传递。数组是C语言中最基本的数据结构之一,掌握它对编程至关重要。下篇将介绍二维数组,敬请期待!
17 0
一文彻底搞明白C语言的数组
一文轻松拿捏C语言的指针的基础使用
本文介绍了C语言中的指针概念,包括直接访问和间接访问内存的方式、指针变量的定义与使用、取址运算符`&`和取值运算符`*`的应用,帮助读者深入理解指针这一C语言的核心概念。君志所向,一往无前!
16 0
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
128 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
262 9
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
73 7
【C语言】两个数组比较详解
比较两个数组在C语言中有多种实现方法,选择合适的方法取决于具体的应用场景和性能要求。从逐元素比较到使用`memcmp`函数,再到指针优化,每种方法都有其优点和适用范围。在嵌入式系统中,考虑性能和资源限制尤为重要。通过合理选择和优化,可以有效提高程序的运行效率和可靠性。
214 6
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
104 5
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
260 3
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。

热门文章

最新文章