C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)二

简介: C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)二

C语言学习记录——7000+字长文-复习&学习指针(指针、地址、指针变量、指针与数组、指针与函数、指针数组、多级指针)一:https://developer.aliyun.com/article/1530354

字符数组与字符指针

可以用字符串常量来给字符型指针进行初始化。

int *str1 = "How are you !";
//此时字符指针指向的是一个字符串常量的首地址,即指向字符串的首地址。
 
int *str2[] = "How are you !";
//此时,str2是字符数组,它存放的是一个字符串。

字符指针str1与字符数组str2的区别是:


str1是一个变量,可以改变str1的值,即str1可以指向不同内存单元的地址。



指针字符数组的指针

定义一个字符指针指向字符数组后,就可以利用指针来处理该字符数组中存储的字符串。使用指针处理字符串,不仅书写方便,而且程序的运行效率更高。

用指针处理字符串的方法是:首先定义一个字符指针,然后将字符数组的首地址赋值给该指针。

例如:

char str[] = "Hello world !";
char *p = str;

看下面一段代码:

#include <stdio.h>
int main()
{
  char str[] = "Hello world !";
  char *p = str;     
  printf("%s\n", p);
  p += 6;
  printf("%s\n", p);
  return 0;
}


其运行结果为:

其中p初始化时存储了str的首地址,故打印出来了完整的字符串。

而后将指针p往后移了6位,使得其新的首地址从‘w’开始,所以打印出来的结果变成了“world!”。

指针与函数

 

函数型指针的定义

在C语言中,定义了函数之后,系统为该函数分配一段连续的存储空间。其中函数的起始地址称为该函数的入口地址,将此地址赋给另外一个变量,则该变量为一个指向函数的指针。

指向函数的指针变量的一般形式为:

类型说明符(* 标识符)();

其中,类型说明符为被指针所指向的函数的返回值的数据类型;标识符为一个指针名(不是函数名),该指针只能指向函数;括号中为空,但括号必须有,表示该指针是专指函数的。

例如:

int (*p)();

函数型指针的赋值

用函数名为指针初始化,表示指针指向该函数。

例如:

int (*p)();   //定义函数型指针
int fun();    //声明函数fun
p = fun;      //让指针p指向函数fun

关于函数型指针的赋值说明:

(1)当函数型指针指向了某一函数后,此函数的调用可以用函数名,也可以用指针(用*p代替原函数名);

(2)用函数型指针定义之后,不是固定指向某一个函数,而是先后指向不同的函数(给它赋值其他入口地址即可改变其指向的函数);

(3)为函数型指针赋值时,不必用参数;

(4)对指向函数的指针变量,先p + n,p ++,p -- 等运算是没有意义的。

指针型函数的定义与使用

调用函数,通常得到一个返回值带回主调函数。如果返回值为一个指针时,则该函数就是指针型函数。

定义形式:

类型说明符  *标识符(形参列表);

例如:

int *a(int x,int y);

其中a是函数名,调用它以后能得到一个指向整型数据的指针。x、y是函数a的形参,为整型。因此,指针型函数也就是返回指针值的函数。

 

利用指针型函数,求一个二维数组中的最大值,并返回它的地址

#include <stdio.h>
#define ROW 3   //宏定义二维数组的行和列
#define COL 4
 
int* max(int a[ROW][COL])
{
  int *p, i, j;
  p = a[0];
  for (i = 0; i < ROW; i++)
  {
    for (j = 0; j < COL; j++)
    {
      //判断大小
      if (*p < *(*(a + i) + j))
        p = *(a + i) + j;
    }
  }
  return p;
}
 
int main()
{
  int a[ROW][COL], i, j, * p;
  printf("请输入二维数组值:");
  for (i = 0; i < ROW; i++)
  {
    for (j = 0; j < COL; j++)
    {
      scanf("%d", &a[i][j]);
    }
  }
  //将二维数组传参进函数a
  p = max(a);
  for (i = 0; i < ROW; i++)
  {
    for (j = 0; j < COL; j++)
    {
      printf("%d\t", a[i][j]);
    }
    printf("\n");
  }
  printf("最大值为:%d\n", *p);
  return 0;
}

其运行结果为:

 

指针数组

由若干个指针变量组成的数组,称为指针数组。指针数组也是数组的一种,所有有关数组的概念都适用它。但指针数组与普通数组又有区别,指针数组的数组元素是指针类型的,只能用来存放地址值。

指针数组的定义

定义形式:

类型说明符  *数组名[数组长度];

例如:

int *p[4];

这条语句定义了一个指针数组p,该数组中有4个元素,每个元素都是一个指针,指向int型数据。指针数组比较适合用来指向若干个字符串,使字符串处理更加方便灵活。


值得注意的是:


指针数组语句:int *p[ 4 ];符号[]的优先级比符号*高,因此变量名p先与[]结合,表示这是一个长度为4的数组;再与*和int结合,表示该数组的元素的数据类型是int * 型,每个数组元素都可以指向一个整型变量。  

指针数组的初始化

指针数组是由若干个指针变量组成的数组,因此必须用地址值为指针数组初始化。

例如:

int arr[3][3] = {1,2,3,4,5,6,7,8,9};
 
int *pa[3] = {arr[0],arr[1],arr[2]};

由于arr是一个二维数组,所以arr[ 0 ],arr[ 1 ],arr[ 2 ]为该二维数组的每一行的首地址。

故而,可以通过指针数组来引用二维数组中的元素:

pa[i] + j = arr[i] + j = &arr[i][j];
 
*(pa[i] + j) = *(arr[i] + j) = arr[i][j]; 

用字符指针数组表示一组字符串,即每个数组元素分别指向一个字符串,然后进行字符串的比较:

 

#include <stdio.h>
#include <string.h>
int main()
{
  char *s[4] = { "hello","Circle","Square","Rectangle" };
  char *temp;
  int i, j, k;
  for (i = 0; i < 4; i++)
  {
    printf("%d:%s\n", i + 1, s[i]);  //按原始顺序输出4个字符串
  }
  for (i = 0; i < 3; i++)
  {
    //使得前一个字符串与后面几个字符串对比
    k = i;
    for (j = i + 1; j < 4; j++)
    {
      if (strcmp(s[k], s[j]) > 0)
        k = j;
      if (k != i)
      {
        temp = s[i];
        s[i] = s[k];
        s[k] = temp;       //交换指针指向的字符串
      }
    }
        
  }
  printf("\n");
  for (i = 0; i < 4; i++)
  {
    printf("%d:%s\n", i + 1, s[i]);   //输出排序后的4个字符串
  }
  return 0;
}

其运行结果为:

 

多级指针

如果一个指针变量存放的是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,即多级指针(指向指针的指针)

多级指针定义的一般形式如下:

类型说明符  * * 指针名;

例如:

int x = 4;
int *p ;
int **p ;
p = &x;   //指针变量p指向整型变量x
q = &p;   //二级指针q指向指针变量p

看下面代码:

#include <stdio.h>
int main()
{
  int x = 10;
  int *p, **q;
  p = &x;
  q = &p;
  printf(" x = %d\n", x);
  printf(" *p = %d\n", *p);
  printf(" **q = %d\n", **q);
  return 0;
}

其运行结果为:

所以说,以上三种方式都是等价的。

要注意的:指向指针的指针是间接地指向目标变量,因此,将直接指向目标变量的指针称为一级指针,将指向指针的指针称为二级指针,将指向二级指针的指针称为三级指针,以此类推。

通过指向指针的指针输出数组元素:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
  srand((unsigned int)time(NULL));
  int arr[5][3],a,b,**p;
  int *num[5] = { arr[0],arr[1],arr[2],arr[3],arr[4] }; //指针数组
  p = num;  //指向指针数组的指针
  for (a = 0; a < 5; a++)   //随机初始化二维数组
  {
    for (b = 0; b < 3; b++)
    {
      arr[a][b] = rand() % 20 + 1;
    }
  }
 
  for (a = 0; a < 5; a++)   
  {
    for (b = 0; b < 3; b++)
    {
      printf("%2d\t", *(*p + b));  //通过二级指针输出数组元素
    }
    printf("\n");
    p++;
  }
  return 0;
}

其运行结果为:

目录
相关文章
|
2月前
|
存储 C语言 C++
如何通过指针作为函数参数来实现函数的返回多个值
在C语言中,可以通过将指针作为函数参数来实现函数返回多个值。调用函数时,传递变量的地址,函数内部通过修改指针所指向的内存来改变原变量的值,从而实现多值返回。
|
2月前
链表指针的传参,传值和传地址
本文讨论了链表操作中指针传参的问题,特别是指针的传值与传地址的区别,并提供了修正代码,以确保链表插入操作能正确地修改指针指向的地址。
17 1
链表指针的传参,传值和传地址
|
2月前
|
存储 搜索推荐 C语言
如何理解指针作为函数参数的输入和输出特性
指针作为函数参数时,可以实现输入和输出的双重功能。通过指针传递变量的地址,函数可以修改外部变量的值,实现输出;同时,指针本身也可以作为输入,传递初始值或状态。这种方式提高了函数的灵活性和效率。
|
2月前
|
存储 编译器 C语言
C语言:数组名作为类型、作为地址、对数组名取地址的区别
在C语言中,数组名可以作为类型、地址和取地址使用。数组名本身代表数组的首地址,作为地址时可以直接使用;作为类型时,用于声明指针或函数参数;取地址时,使用取地址符 (&),得到的是整个数组的地址,类型为指向该类型的指针。
|
2月前
|
存储 C语言
C语言:设置地址为 0x67a9 的整型变量的值为 0xaa66
在C语言中,可以通过指针操作来实现对特定地址的访问和赋值。要将地址为 0x67a9 的整型变量值设为 0xaa66,可以先定义一个指向该地址的指针,并通过该指针对该内存位置进行赋值操作。需要注意的是,直接操作内存地址具有一定风险,必须确保地址合法且可写。代码示例应考虑字节序及内存对齐问题。
|
2月前
利用指针函数
【10月更文挑战第2天】利用指针函数。
19 1
|
2月前
|
C++
析构造函数就是为了释放内存,就是在局部指针消失前释放内存,拷贝构造函数就是以构造函数为模块,在堆里面新开一块,同一个变量在堆里面的地址
本文讨论了C++中构造函数和析构函数的作用,特别是它们在管理动态内存分配和释放中的重要性,以及如何正确地实现拷贝构造函数以避免内存泄漏。
40 2
|
2月前
|
C语言
教你快速理解学习C语言的循环与分支
教你快速理解学习C语言的循环与分支
17 0
|
2月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
32 0
|
2月前
|
C语言
学习——理解指针(4)(指针学习最后一节)
学习——理解指针(4)(指针学习最后一节)