C语言 指针



  • 指针

    C语言中的指针简单易学。使用指针可以更轻松地执行某些C编程任务,而如果不使用指针则无法执行其他任务(例如动态内存分配)。因此,有必要学习指针成为理想的C程序员。让我们以简单轻松的步骤开始学习它们。如您所知,每个变量都是一个内存位置,并且每个内存位置都定义了其地址,可以使用&运算符(&)进行访问,该地址表示内存中的地址。考虑以下示例,该示例显示定义的变量的地址-
    
    #include <stdio.h>
    
    int main () {
    
       int  var1;
       char var2[10];
    
       printf("Address of var1 variable: %x\n", &var1  );
       printf("Address of var2 variable: %x\n", &var2  );
    
       return 0;
    }
    
    
  • 什么是指针?

    指针是一个变量,其值是另一个变量的地址,即存储位置的直接地址。像任何变量或常量一样,您必须在使用指针存储任何变量地址之前声明一个指针。指针变量声明的一般形式是-
    
    type *var-name;
    
    
    在这里,type是指针的基本类型。它必须是有效的C数据类型,并且var-name是指针变量的名称。用于声明指针的星号*与用于乘法的星号相同。但是,在此语句中,星号用于将变量指定为指针。看看一些有效的指针声明-
    
    int    *ip;    /* pointer to an integer */
    double *dp;    /* pointer to a double */
    float  *fp;    /* pointer to a float */
    char   *ch     /* pointer to a character */
    
    
    所有指针的值的实际数据类型(无论是整数,浮点数,字符还是其他形式)都是相同的,即表示内存地址的十六进制数字。不同数据类型的指针之间的唯一区别是指针指向的变量或常量的数据类型。
  • 如何使用指针?

    有一些重要的操作,我们将非常频繁地在指针的帮助下进行操作。
    • (a)我们定义了一个指针变量,
    • (b)将变量的地址分配给指针,
    • (c)最后访问指针变量中可用地址处的值。
    这是通过使用一元运算符*完成的,该运算符返回变量的值,该变量位于其操作数指定的地址处。以下示例利用这些操作-
    
    #include <stdio.h>
    
    int main () {
    
       int  var = 20;   /* actual variable declaration */
       int  *ip;        /* pointer variable declaration */
    
       ip = &var;  /* store address of var in pointer variable*/
    
       printf("Address of var variable: %x\n", &var  );
    
       /* address stored in pointer variable */
       printf("Address stored in ip variable: %x\n", ip );
    
       /* access the value using the pointer */
       printf("Value of *ip variable: %d\n", *ip );
    
       return 0;
    }
    
    
  • 空指针

    在没有确切地址要分配的情况下,将NULL值分配给指针变量始终是一个好习惯。这是在变量声明时完成的。分配了NULL的指针称为空指针。NULL指针是在几个标准库中定义的值为零的常量。考虑以下程序-
    
    #include <stdio.h>
    
    int main () {
    
       int  *ptr = NULL;
    
       printf("The value of ptr is : %x\n", ptr  );
     
       return 0;
    }
    
    
    在大多数操作系统中,程序不允许访问地址0处的内存,因为该内存是由操作系统保留的。但是,内存地址0具有特殊意义;它表示指针不打算指向一个可访问的内存位置。但按照惯例,如果指针包含null(零)值,则假定它不指向任何东西。要检查空指针,可以使用“if”语句,如下所示
    
    if(ptr)     /* succeeds if p is not null */
    if(!ptr)    /* succeeds if p is null */
    
    
  • 指针详细知识

    指针有许多但很简单的概念,它们对C编程非常重要。任何C程序员都应该清楚以下重要的指针概念-
    指针算术 - 指针中可以使用四种算术运算符:++,-,+,-
    指针是一个地址,它是一个数值。因此,您可以像对数值一样对指针执行算术运算。可以在指针上使用四种算术运算符:++,-,+和-
    为了理解指针算术,让我们考虑ptr是一个指向地址1000的整数指针。假设32位(4字节)整数,让我们对指针执行以下算术运算-
    
    ptr++
    
    
    在上述操作之后,由于ptr每次递增,因此ptr将指向位置1004,它将指向下一个整数位置,即当前位置旁边的4个字节。此操作将指针移到下一个存储位置,而不会影响该存储位置的实际值。如果ptr指向地址为1000的字符(char),则上述操作将指向位置1001,因为下一个字符将在1001处可用(因为char类型只占用一个字节)。
    递增指针
    我们更喜欢在程序中使用指针而不是数组,因为变量指针可以递增,这与数组名不同,因为数组名是常量指针,因此不能递增。以下程序递增变量指针以访问数组的每个后续元素-
    
    #include <stdio.h>
    
    const int MAX = 3;
    
    int main () {
    
       int  var[] = {10, 100, 200};
       int  i, *ptr;
    
       /* let us have array address in pointer */
       ptr = var;
            
       for ( i = 0; i < MAX; i++) {
    
          printf("Address of var[%d] = %x\n", i, ptr );
          printf("Value of var[%d] = %d\n", i, *ptr );
    
          /* move to the next location */
          ptr++;
       }
            
       return 0;
    }
    
    
    递减指针
    相同的注意事项适用于递减指针,指针的值按其数据类型的字节数减少,如下所示-
    
    #include <stdio.h>
    
    const int MAX = 3;
    
    int main () {
    
       int  var[] = {10, 100, 200};
       int  i, *ptr;
    
       /* let us have array address in pointer */
       ptr = &var[MAX-1];
            
       for ( i = MAX; i > 0; i--) {
    
          printf("Address of var[%d] = %x\n", i-1, ptr );
          printf("Value of var[%d] = %d\n", i-1, *ptr );
    
          /* move to the previous location */
          ptr--;
       }
            
       return 0;
    }
    
    
    指针比较
    可以通过使用关系运算符(例如==,<和>)来比较指针。如果p1和p2指向彼此相关的变量(例如同一数组的元素),则可以有意义地比较p1和p2。下面的程序修改了前面的示例- 通过递增变量指针,只要它指向的地址小于或等于数组的最后一个元素的地址,即&var [MAX-1]
    
    #include <stdio.h>
    
    const int MAX = 3;
    
    int main () {
    
       int  var[] = {10, 100, 200};
       int  i, *ptr;
    
       /* let us have address of the first element in pointer */
       ptr = var;
       i = 0;
            
       while ( ptr <= &var[MAX - 1] ) {
    
          printf("Address of var[%d] = %x\n", i, ptr );
          printf("Value of var[%d] = %d\n", i, *ptr );
    
          /* point to the next location */
          ptr++;
          i++;
       }
            
       return 0;
    }
    
    
    指针数组 - 您可以定义数组以容纳多个指针。
    
    int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
    
    
    在理解指针数组的概念之前,让我们考虑以下示例,该示例使用3个整数的数组-
    
    #include <stdio.h>
    
    const int MAX = 3;
     
    int main () {
    
       int  var[] = {10, 100, 200};
       int i;
     
       for (i = 0; i < MAX; i++) {
          printf("Value of var[%d] = %d\n", i, var[i] );
       }
       
       return 0;
    }
    
    
    在某些情况下,我们想要维护一个数组,该数组可以存储指向int或char或任何其他可用数据类型的指针。以下是指向整数的指针数组的声明-
    
    int *ptr[MAX];
    
    
    它将ptr声明为MAX整数大小指针的数组。因此,ptr中的每个元素都持有一个指向int值的指针。以下示例使用三个整数,它们存储在指针数组中,如下所示:
    
    #include <stdio.h>
     
    const int MAX = 3;
     
    int main () {
    
       int  var[] = {10, 100, 200};
       int i, *ptr[MAX];
     
       for ( i = 0; i < MAX; i++) {
          ptr[i] = &var[i]; /* assign the address of integer. */
       }
       
       for ( i = 0; i < MAX; i++) {
          printf("Value of var[%d] = %d\n", i, *ptr[i] );
       }
       
       return 0;
    }
    
    
    您还可以使用指向字符的指针数组来存储字符串列表,如下所示:
    
    #include <stdio.h>
    
    const int MAX = 4;
     
    int main () {
    
       char *names[] = {
          "Zara Ali",
          "Hina Ali",
          "Nuha Ali",
          "Sara Ali"
       };
       
       int i = 0;
    
       for ( i = 0; i < MAX; i++) {
          printf("Value of names[%d] = %s\n", i, names[i] );
       }
       
       return 0;
    }
    
    
    多重指针- C允许您将指针放在指针上。
    指向指针的指针是多种间接形式或一系列指针。通常,指针包含变量的地址。当我们定义一个指向指针的指针时,第一个指针包含第二个指针的地址,该地址指向包含实际值的位置,如下所示。
    pointer
    作为指针的指针的变量必须这样声明。这是通过在其名称前面放置一个额外的星号来完成的。例如,以下声明声明了一个指向int类型的指针的指针-
    
    int **var;
    
    
    当指向指针的指针间接指向目标值时,访问该值需要两次应用星号运算符,如下面的示例所示-
    
    #include <stdio.h>
    
    int main () {
    
       int  var;
       int  *ptr;
       int  **pptr;
    
       var = 3000;
    
       /* take the address of var */
       ptr = &var;
    
       /* take the address of ptr using address of operator & */
       pptr = &ptr;
    
       /* take the value using pptr */
       printf("Value of var = %d\n", var );
       printf("Value available at *ptr = %d\n", *ptr );
       printf("Value available at **pptr = %d\n", **pptr);
    
       return 0;
    }
    
    
    将指针传递给C中的函数 - 通过引用或地址传递参数可以使被调用函数在调用函数中更改传递的参数。
    C编程允许将指针传递给函数。为此,只需将函数参数声明为指针类型。 以下是一个简单的示例,其中我们将无符号长指针传递给函数,并更改函数内部的值,该值会在调用函数中反映出来-
    
    #include <stdio.h>
    #include <time.h>
     
    void getSeconds(unsigned long *par);
    
    int main () {
    
       unsigned long sec;
       getSeconds( &sec );
    
       /* print the actual value */
       printf("Number of seconds: %ld\n", sec );
    
       return 0;
    }
    
    void getSeconds(unsigned long *par) {
       /* get the current number of seconds */
       *par = time( NULL );
       return;
    }
    
    
    该函数可以接受一个指针,也可以接受一个数组,如以下示例所示:
    
    #include <stdio.h>
    
    
    /* function declaration */
    double getAverage(int *arr, int size);
     
    int main () {
    
       /* an int array with 5 elements */
       int balance[5] = {1000, 2, 3, 17, 50};
       double avg;
     
       /* pass pointer to the array as an argument */
       avg = getAverage( balance, 5 ) ;
     
       /* output the returned value  */
       printf("Average value is: %f\n", avg );
       return 0;
    }
    
    double getAverage(int *arr, int size) {
    
       int  i, sum = 0;       
       double avg;          
     
       for (i = 0; i < size; ++i) {
          sum += arr[i];
       }
     
       avg = (double)sum / size;
       return avg;
    }
    
    
    从C函数返回指针 - C允许函数返回指向局部变量,静态变量和动态分配的内存的指针。
    ,我们已经了解了C编程如何允许从函数返回数组。同样,C还允许从函数返回指针。为此,您必须声明一个返回指针的函数,如以下示例所示:
    
    int * myFunction() {
       .
       .
       .
    }
    
    
    要记住的第二点是,在函数外部返回局部变量的地址不是一个好主意,因此您必须将局部变量定义为静态变量。现在,考虑以下函数,该函数将生成10个随机数,并使用表示指针的数组名称(即第一个数组元素的地址)返回它们。
    
    #include <stdio.h>
    #include <time.h>
     
    /* function to generate and return random numbers. */
    int * getRandom( ) {
    
       static int  r[10];
       int i;
     
       /* set the seed */
       srand( (unsigned)time( NULL ) );
            
       for ( i = 0; i < 10; ++i) {
          r[i] = rand();
          printf("%d\n", r[i] );
       }
     
       return r;
    }
     
    /* main function to call above defined function */
    int main () {
    
       /* a pointer to an int */
       int *p;
       int i;
    
       p = getRandom();
            
       for ( i = 0; i < 10; i++ ) {
          printf("*(p + [%d]) : %d\n", i, *(p + i) );
       }
     
       return 0;
    }