数组指针、函数指针、二级指针、字符串函数

简介: 数组指针、函数指针、二级指针、字符串函数

数组指针

#include <stdio.h>
int getTheData(int (*p)[4],int hang,int lie)//(*p)[4]是数组指针
{
  int data;
  data = *(*(p+hang)+lie);//将对应数组中的值找出来
  return data;
  //return p[hang][lie];//同理 将对应数组中的值找出来
}
void tipsInputHangLie(int *pm, int *pn)//形参中的变量类型要与实参中相同,都是int
{
  printf("输入行列值:\n");
  scanf("%d%d",pm,pn);//指针就是地址,对相应的地址进行操作
  puts("done!");
}
//arr,arr[0]
int main()
{
  int arr[3][4] = {{11,22,33,44},{12,13,15,16},{22,66,77,88}};//arr+
  int ihang,ilie;
  int data;
  //1. 提示用户输入行列值
  tipsInputHangLie(&ihang,&ilie);//对地址进行操作,所以函数中的操作能改变ihang和ilie的值
  //2. 找出对应行列值的那个数
  data = getTheData(arr,ihang,ilie);//arr是数组的地址,也就是指针
  //3. 打印出来
  printf("%d行%d列的值是%d\n",ihang,ilie,data);
}

输出内容

c61f25dc176f4444807ffd20f436ae2d.png

函数指针

回掉函数的底层逻辑就是函数指针

#include <stdio.h>
#include <stdlib.h>
int getMax(int data1, int data2)
{
  return data1>data2 ? data1:data2;
}
int getMin(int data1, int data2)
{
  return data1<data2 ? data1:data2;
}
int getSum(int data1, int data2)
{
  return data1+data2;
}
int dataHandler(int data1, int data2, int (*pfunc)(int, int ))//第三个形参是函数指针,函数指针中对类型有要求,形参名可省略
{
  int ret;
  ret = (*pfunc)(data1,data2);//调取函数,求得返回值
  return ret;
}
int main()
{ 
  int a = 10;
  int b = 20;
  int cmd;
  int ret;
  int (*pfunc)(int , int );
  printf("请输入1(取大值),2(取小值),或者3(求和)\n");
  scanf("%d",&cmd);
  switch(cmd){
    case 1:
      pfunc = getMax;//对地址进行了更改,也就变化了对应的值
    break;
    case 2:
      pfunc = getMin;
    break;
    case 3:
      pfunc = getSum;
    break;
    default:
      printf("输入错误!@输入1(取大值),2(取小值),或者3(求和)\n");
      exit(-1);//异常退出
    break;
  }
  ret = dataHandler(a,b,pfunc);//pfunc获取了对应的函数名,第三个实参pfunc是函数指针的地址
  printf("ret = %d\n",ret);
  return 0;
}

输出内容

4acfd64df956404bbec1bb78bbd34ec4.png

函数指针数组

#include <stdio.h>
#include <stdlib.h>
int getMax(int data1, int data2)
{
  return data1>data2 ? data1:data2;
}
int getMin(int data1, int data2)
{
  return data1<data2 ? data1:data2;
}
int getSum(int data1, int data2)
{
  return data1+data2;
}
int main()
{ 
  int a = 10;
  int b = 20;
  int ret;
  int (*pfunc[3])(int , int )={
    getMin,
    getMax,
    getSum};//函数指针数组!初始化,将数组中的值(这个值是个地址,也就是指针,这个指针是个函数指针,将三个函数地址放在数组里)
  for(int i=0;i<3;i++){
    ret = (*pfunc[i])(a,b);//遍历数组中的三个函数指针,获取返回值
    printf("ret = %d\n",ret);
  }
  return 0;
}

输出内容

d5449960628c4674acb8ffc4ff47aca7.png

函数指针

#include <stdio.h>
int* getPosPerson(int pos, int (*pstu)[4])//函数指针,返回指针的函数
{
  int *p;
  p = (int *)(pstu+pos);//二维数组地址+输入的数就是对应的数组值,然后赋值给P
  return p;
}
int main()
{
  int scores[3][4]={
    {55,66,77,88},//学生1
    {66,55,99,100},//学生2
    {11,22,33,59},//学生3
  };
  int *ppos;
  int pos;
  printf("请输入你需要看的学生号数:0,1,2\n");
  scanf("%d",&pos);
  ppos = getPosPerson(pos, scores);//获取对应数组的地址
  for(int i=0;i<4;i++){//将小数组里面的值进行遍历出来输出
    printf("%d ",*ppos++);//++代表偏移一个int整形的字节数
  }
  return 0;
}

输出内容

770be62d8af5451584a97887d494e5f3.png

二级指针

#include <stdio.h>
void getPosPerson(int pos, int (*pstu)[4],int **ppos)//函数指针,返回指针的函数
{
  *ppos = (int *)(pstu+pos);//用二级指针的目的是直接修改了MAIN函数中的ppos的值
}
int main()
{
  int scores[3][4]={
    {55,66,77,88},
    {66,55,99,100},
    {11,22,33,59},
  };
  int *ppos;
  int pos;
  printf("请输入你需要看的学生号数:0,1,2\n");
  scanf("%d",&pos);
  getPosPerson(pos, scores,&ppos);
  for(int i=0;i<4;i++){
    printf("%d ",*ppos++);
  }
  return 0;
}

输出内容image.png

在新版的C语言中出现了断言函数assert

assert() 的用法很简单,我们只要传入一个表达式,它会计算这个表达式的结果:

如果表达式的结果为“假”,assert() 会打印出断言失败的信息,并调用 abort() 函数终止程序的执行;

如果表达式的结果为“真”,assert() 就什么也不做,程序继续往后执行。

#include <stdio.h>
#include <assert.h>
char* myStrcpy(char *des, char *src)
{
  //assert 的作用是现计算表达式 expression ,如果其值为假(即为0),
  //那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行
  assert(des != NULL && src != NULL);//断言
  char *bak = des;
  while( *src != '\0'){
    *des = *src;
    des++;
    src++;
  }
  *des = '\0';
  return bak;
}
char* myStrcpy2(char *des, char *src)
{
  if(des == NULL || src == NULL){
    return NULL;
  }
  char *bak = des;
  while( *src != '\0'){
    *des++ = *src++;
  }
  *des = '\0';
  return bak;
}
char* myStrcpy3(char *des, char *src)
{
  if(des == NULL || src == NULL){
    return NULL;
  }
  char *bak = des;
  while( (*des++ = *src++) != '\0');
  *des = '\0';
  return bak;
}
char* myStrncpy(char *des, char *src, int count)
{
  if(des == NULL || src == NULL){
    return NULL;
  }
  char *bak = des;
  while( *src != '\0' && count>0){
    *des++ = *src++;
    count--;
  }
  if(count > 0){
    while(count > 0){
      count--;
      *des++ = '\0';
    }
    return des;
  }
  *des = '\0';
  return bak;
}
int main()
{
  char str[128] = {'\0'};
  char *pstr = NULL;
  char a = 'm';
  char b;
  if((b=a) == 'm'){
    printf("ok\n");
  }
  char *p = "chenlichen handsome";
  myStrcpy(pstr, p);//这么一拷贝显然是假,P不为NULL,所以打印错误LOG信息,结束程序
  puts(str);
  return 0;
}

输出结果:

ok
Assertion failed: des != NULL && src != NULL, file 1.c, line 7

字符串拼接函数strcat

#include <stdio.h>
#include <string.h>
int main()
{
  char str[128] = "liuzhihao";
  char *p = "xiaohao";
  char *p2;
    p2 = strcat(str,p);
  puts(str);
  puts(p2);
  return 0;
}

输出结果

liuzhihaoxiaohao
liuzhihaoxiaohao

多种写法实现strcat

#include <stdio.h>
#include <string.h>
#include <assert.h>
char* myStrcat(char *des, char *src)
{
  assert( des!=NULL && src!=NULL);
  char *bak = des;
  while(*des){
    des++;
  }
  while((*des++ = *src++) != '\0');
  *des = '\0';
  return bak;
}
char* myStrcat2(char *des, char *src)
{
  char *bak = des;
  strcpy(des+strlen(des),src);
  return bak;
}
char* myStrcat3(char *des, char *src)
{
  assert( des!=NULL && src!=NULL);
  char *bak = des;
  for(;*des!='\0';des++);
  while((*des++ = *src++) != '\0');
  *des = '\0';
  return bak;
}
int main()
{
  char str[128] = "liuzhihao";
  char *p2;
  char *p = " xiaohao";
  p2 = myStrcat(str,p);
  //p2 = strcat(str,p);
  puts(str);
  //puts(p2);
  return 0;
}

strcmp函数

#include <stdio.h>
#include <string.h>
#include <assert.h>
int myStrcmp(char *str1, char *str2)
{
  int ret = 0;
  int n_str1 = 0;
  int n_str2 = 0;
  char *bakStr1 = str1;
  char *bakStr2 = str2;
  while( *str1 && *str2 && (*str1 == *str2)){
    str1++;
    str2++;
  }
  if(*str1 || *str2){
    str1 = bakStr1;
    str2 = bakStr2;
    while(*str1){
      n_str1 += *str1;
      str1++;
    }
    while(*str2){
      n_str2 += *str2;
      str2++;
    }
  }
  ret = n_str1 - n_str2;
  if(ret < 0){
    ret = -1;
  }
  if(ret > 0){
    ret = 1;
  }
  return ret;
}
int main()
{
  char *p1 = "chmnlichend";
  char *p2 = "chenlzchend";
  int ret = myStrcmp(p1,p2);//-1 1 0
  int ret = strcmp(p1,p2);//-1 1 0
  if(ret == 0){
    puts("相同");
  }
  printf("RET = %d\n",ret);
  return 0;
}

结构体指针

#include <stdio.h>
struct Test
{
  int idata;
  char cdata;
};
int main()
{
  int  var = 20;  
    int  *ip;     
    ip = &var; 
  printf("ip%d\n", *ip);//这里是用*号是因为,变量就是指针,也就是地址
    struct Test t1 = {10, 'c'}; //1. 类型 2.名 3.值 4.地址
    struct Test *ps;
  ps = &t1;
    printf("t1的idata=%d\n",t1.idata);//变量名访问,用点运算符
  printf("t1的idata=%d\n",ps->idata);//这里ps->idata的前面没用*,因为结构体成员是int型的,所以不用*,取决于结构体成员的类型,用.还是用->取决于结构体是指针还是普通变量
  return 0;
}
相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
38 3
|
29天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
1月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
1月前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
1月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
1月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
60 4
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
50 2
|
1月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
39 1
|
2月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
2月前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。