初学者对C语言中指针的爱恨情仇

Posted 手撕代码八百里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初学者对C语言中指针的爱恨情仇相关的知识,希望对你有一定的参考价值。

C语言中指针和数组的爱恨情仇

一、前言

你可能会有小疑问,爱什么?恨什么?

先说恨吧,相信刚学C语言的同志都恨过。

记得大一时,C语言老师上课时用的VC++6.0,记得考试时用的VC++6.0,当时真的咬牙切齿,你说能不恨吗。

没有代码提示,直接劝退了!

刚考完C语言的时候,真的想过这辈子再也不碰C了。

大二下学期,学了Java,授课老师用的Eclipse,虽然老师上课手撸代码,但是我们写作业,考试起码有提示呀,顿时喜欢上了。

就这样,大学期间搞了四年的Java。

那么爱什么呢?

爱的是,我大学毕业后缺搞起C语言,做了嵌入式Linux开发,因为我非常喜欢Linux。

C语言可以直接操作硬件的,那么你可能会问,一个编程语言怎么能和硬件想关联呢?是不是很神奇。

我一开始也不知道,后来经过在公司的一段时间内接触了HDMI、DVI、VGA等信号的驱动知识才了解到,C语言是可以直接操作寄存器的。但是也不能直接操作,而是通过一些特定的协议规则,例如:I2C协议。

搞嵌入式还是挺有好处的,没有Java加班多是真的,下午下班回家、周六、周日、年假基本上不加班,也没办法加班,因为设备是在公司,你没办法拿到家里来对吧。只能回家学习了。想加班的话,还得看公司,至少我们公司965,还是挺爽的。选择生活,还是选择其他还是看自己。

即使不爱,也得爱呀,哈哈哈哈。

二、为什么学指针

  • 1、因为不会,基本用法都不会;
  • 2、因为很想会,必须得懂;
  • 3、因为会用到,必须得学;

不会C语言的指针,你去刷个算法题,去瞧瞧。

哈哈,记得我下定决心搞嵌入式Linux开发的时候,第一次想使用C语言去刷算法题的时候,因为想提升一下自己的C语言的基础。

就打开的一个最最最简单的题:

在这里插入图片描述
在这里插入图片描述

给的初始代码如下:

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){

}

我滴个乖乖,这简直了,直接头大了,没错,直接劝退了。

再来看一下Java版的:

class Solution {
    public int[] twoSum(int[] nums, int target) {

    }
}

哎,好爽快呀。

你就说吧,你不会指针,你怎么去用C语言刷算法题?????
在这里插入图片描述

三、说明

本篇文章不长篇大论的研究指针背后的原理,因为博主还没到这地步。只是简单的总结一下我段时间学到的技巧用法等。

四、跟我一起学

(一)C语言中的*和&

引用我其他博文中的一段话

1、C语言中为什么存在&和*

C语言中大名鼎鼎的“指针”,想必你肯定听说过吧。
没错,C语言中的&和*就是为了指针而诞生的。

指针说白了就是直接/间接的操作(取/存)存储中的地址中的数据。

试想一下,如果没有&和*的存在,你可能每天都在为计算和寻找某个变量在哪里而发愁呢!

有了&和*之后,就不需要你手动的去计算内存中的地址。

2、&和*是什么?

&取地址运算符;
*间接寻址,也可以称为取值运算符,这样就好理解了运算符;

&的作用:如果想找到变量的地址,可以使用&(取地址)运算符。

*的作用:如果你学过链表,你经常会用到:

p->q;

那么p就是指向q的地址。

如果你学过计算机组成原理或者操作系统,里面的寄存器的寻址方式,就有间接寻址方式。

间接寻址方式:说白了就是取这个地址指向的地址的值。

如果有一个变量p,那么p就是取p指向地址的值。

3、&(取地址运算符)和*(间接寻址运算符)的使用

int i; 是变量

int *pi;是指针

 int i, *pi;
 char c,*pc;

例子:

#include <stdio.h>

int main()
{
	int i, *pi;
	char c,*pc;
		
	//初始化i为10
	i = 10;

	//初始化c为‘a’字符
	c = 'a';

	//把pi指向i的地址
	pi = &i;

	//把pc指向c的地址
	pc = &c;

	printf("i=%d;c=%c\\n",*pi,*pc);

	//做一些基本处理
	*pi = *pi + 100;

	printf("*pi+100=%d\\n",*pi);

	
	printf("pi addr=%p;i addr=%p;pc addr=%p;c addr=%p\\n",pi,&i,pc,&c);
	
	

	return 0;
}

执行结果:

i=10;c=a
*pi+100=110
pi addr=0x7ffe76034684;i addr=0x7ffe76034684;pc addr=0x7ffe76034683;c addr=0x7ffe76034683

(二)初识指针和变量

1、变量

(1)变量如何创建

zhenghui@zhlinux:~/codeProject/20210719$ cat test1.c -n 
     1	#include <stdio.h>
     2	
     3	int main()
     4	{
     5	
     6	
     7		//定义int类型的变量
     8		int i1,i2,i3;
     9		//定义double类型的变量
    10		double d1,d2,d3;
    11	
    12		return 0;
    13	}
zhenghui@zhlinux:~/codeProject/20210719$ 

如上所示代码中的【数据类型 空格 变量名 ;】轻轻松松就定义出来了1-N个变量。

(2)变量如何赋值

        //初始化变量
        i1 = 5;
        i2 = 2;
        i3 = 1;

公式:【变量名 = 值;

意思是把什么内容保存到什么变量中。

你是不是有疑问了,区区一个小小滴变量这是如何保存的呢?别急,继续看吧骚年。

(3)变量如何使用

zhenghui@zhlinux:~/codeProject/20210719$ 
zhenghui@zhlinux:~/codeProject/20210719$ cat test1.c 
#include <stdio.h>
int main()
{
	//定义int类型的变量
	int i1,i2,i3;
	//初始化变量
	i1 = 5;
	i2 = 2;
	i3 = 1;
	
	printf("i1=%d,i2=%d,i3=%d\\n",i1,i2,i3);
	return 0;
}
zhenghui@zhlinux:~/codeProject/20210719$ zhenghui@zhlinux:~/codeProject/20210719$ 
zhenghui@zhlinux:~/codeProject/20210719$ 
zhenghui@zhlinux:~/codeProject/20210719$ gcc test1.c 
zhenghui@zhlinux:~/codeProject/20210719$ 
zhenghui@zhlinux:~/codeProject/20210719$ ./a.out 
i1=5,i2=2,i3=1
zhenghui@zhlinux:~/codeProject/20210719$ 

2、指针

(1)指针如何创建

 //定义int类型的指针
 int *p1,*p2,*p3;

(2)指针如何赋值

//定义int类型的变量
int i1,i2,i3;

//初始化变量
i1 = 5;
.......

//定义int类型的指针
int *p1,*p2,*p3;

//赋值
p1 = &i1;

等等

请留步,这里说一下。

指针,其实就是存的地址。

不信可以使用printf大法看看:

zhenghui@zhlinux:~/codeProject/20210719$ 
zhenghui@zhlinux:~/codeProject/20210719$ cat test2.c 
#include <stdio.h>

int main()
{
	//定义int类型的变量
	int i1,i2,i3;

	//初始化变量
	i1 = 5;
	i2 = 2;
	i3 = 1;

	printf("i1=%d,i2=%d,i3=%d\\n",i1,i2,i3);

	//定义int类型的指针
	int *p1,*p2,*p3;

	//赋值
	p1 = &i1;

	//打印
	printf("p1=%p,&i1=%p\\n",p1,&i1);
	return 0;
}
zhenghui@zhlinux:~/codeProject/20210719$ 
zhenghui@zhlinux:~/codeProject/20210719$ ./a.out 
i1=5,i2=2,i3=1
p1=0x7ffde7e3f364,&i1=0x7ffde7e3f364
zhenghui@zhlinux:~/codeProject/20210719$ 

可以看到,我用p1=&i1,打印的结果是相同的,所以可以得到结论。

一个错误的示范:

int *p1;
p1 = 10;

我在没具体学习指针的时候,就这样做过。

编译的时候:

所以:

  • 指针变量只能接收某个内存中的地址;
  • 只能把地址赋值给指针变量。
zhenghui@zhlinux:~/codeProject/20210719$ 
zhenghui@zhlinux:~/codeProject/20210719$ gcc test2.c 
test2.c: In function ‘main’:
test2.c:23:5: warning: assignment to ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
   23 |  p2 = 123;
      |     ^
zhenghui@zhlinux:~/codeProject/20210719$ 

(3)指针如何使用

这里只需要学会*&就行了,其余的暂时可以不用管。

(三)指针的一些基本用法

1、指针和变量的定义

//变量定义
int i,j,k;

//指针的定义
int *pi,*pj,*pk;

2、指针和变量的初始化

//变量定义
int i,j,k;

//指针的定义
int *pi,*pj,*pk;


//变量的初始化
i = 10;
j = 100;
k = 1000;

//指针的初始化
pi = &i;
pj = &j;
pk = &k;

如果你还不知道&和*的用法和作用,可以参考我这篇:
《C语言中的&和*》

3、指针如何作为参数

#include <stdio.h>

void maxV(int a,int b,int *max)
{
	if( a > b)
	{
		*max = a; 
	}else
	{
		*max = b;
	}
}

int main()
{
	//变量定义
	int i,j,k;

	//指针的定义
	int *pi,*pj,*pk;


	//变量的初始化
	i = 10;
	j = 100;
	k = 1000;

	//指针的初始化
	pi = &i;
	pj = &j;
	pk = &k;

	int max;

	maxV(i,j,&max);

	printf("最大的数是:%d\\n",max);
	
	return 0;
}

结果:

最大的数是:100

4、指针如何作为返回值

#include <stdio.h>

void maxV(int a,int b,int *max)
{
        if( a > b)
        {
                *max = a;
        }else
        {
                *max = b;
        }
}

int *maxV2(int *a,int *b)
{
        return *a > *b ? a : b;
}

int main()
{
        //变量定义
        int i,j,k;

        //指针的定义
        int *pi,*pj,*pk;


        //变量的初始化
        i = 10;
        j = 100;
        k = 1000;

        //指针的初始化
        pi = &i;
        pj = &j;
        pk = &k;

        int max;

        maxV(i,j,&max);

        printf("最大的数是:%d\\n",max);


        printf("最大的数是:%d\\n",*maxV2(&j,&k));

        return 0;
}

结果:

最大的数是:100
最大的数是:1000

5、案例1:完成swap函数,完成两个参数交换的功能

zhenghui@zhlinux:~/codeProject/11指针$ 
zhenghui@zhlinux:~/codeProject/11指针$ cat swap.c 
#include <stdio.h>

void swap(int *p,int *q)
{
	int temp = *p;
	*p = *q;
	*q = temp;
}

int main()
{
	
	int a=10;
	int b=20;

	swap(&a,&b);

	printf("a=%d,b=%d\\n",a,b);

	return 0;
}
zhenghui@zhlinux:~/codeProject/11指针$ 
zhenghui@zhlinux:~/codeProject/11指针$ 
zhenghui@zhlinux:~/codeProject/11指针$ ./a.out 
a=20,b=10
zhenghui@zhlinux:~/codeProject/11指针$ 

6、案例2:找到最大和第二大的值

题目如下:
在这里插入图片描述
方法一:两次循环

第一次:找出最大的值,然后记录下来最大值的位置;
第二次查找的时候把最大值的位置的数据给清空,继续寻找最大的值,那么这一次的最大的值就是第二大的。

#include <stdio.h>
#define ARRAY_SIZE(array) ((int) (sizeof(array) / sizeof(array[0]) ))

/*
 *查找最大的值和第二大的值
 * */
void find_tow_largest(int a[],int n,int *largest,int *second_largest)
{

        //1、找到最大的值
        *largest = a[0];
        //记录下来最大的值的位置
        int maxIndex = 0;

        for(int i = 1;i<n;i++)
        {
                if(*largest < a[i])
                {
                        *largest = a[i];

                        maxIndex = i;
                }
        }

        //2、找第二大的值

        //把最大的值变成最小的值
        a[maxIndex] = -1;
        *second_largest = a[0];

        for(int i = 1;i<n;i++)
        {
                if(*second_largest < a[i])
                {
                        *second_largest = a[i];
                }
"find_tow_larget.c" 54L, 863C                                                              31,2-9       顶端
                        *largest = a[i];

                        maxIndex = i;
                }
        }

        //2、找第二大的值

        //把最大的值变成最小的值
        a[maxIndex] = -1;
        *second_largest = a[0];

        for(int i = 1;i<n;i++)
        {
                if(*second_largest < a[i])
                {
                        *second_largest = a[i];
                }
        }

}

int main()
{
        int a[] = {1,5,2,4,7,5,8,234};

        int n = ARRAY_SIZE(a);

        int largest,second_largest;

        find_tow_largest(a,n,&largest,&second_largest);

        printf("最大的是:%d,第二大的是:%d\\n",largest,second_largest);

        return 0;
}

执行结果:

zhenghui@zhlinux:~/codeProject/11指针$ vim find_tow_larget.c
zhenghui@zhlinux:~/codeProject/11指针$
zhenghui@zhlinux:~/codeProject/11指针$
zhenghui@zhlinux:~/codeProject/11指针$ gcc find_tow_larget.c
zhenghui@zhlinux:~/codeProject/11指针$
zhenghui@zhlinux:~/codeProject/11指针$ ./a.out
最大的是:234,第二大的是:8
zhenghui@zhlinux:~/codeProject/11指针$

方法2:排序

可以利用数组的排序来做,任何排序都可以。

这里选用插入排序来做。

zhenghui@zhlinux:~/codeProject/11指针$
zhenghui@zhlinux:~/codeProject/11指针$ cat find_tow_larget.c
#include <stdio.h>
#define ARRAY_SIZE(array) ((int) (sizeof(array) / sizeof(array[0]) ))

/*
 *查找最大的值和第二大的值
 * */
void find_tow_largest(int a[],int n,int *largest,int *second_largest)
{

	//1、找到最大的值
	*largest = a[0];
	//记录下来最大的值的位置
	int maxIndex = 0;

	for(int i = 1;i<n;i++)
	{
		if(*largest < a[i])
		{
			*largest = a[i];

			maxIndex = i;
		}
	}

	//2、找第二大的值

	//把最大的值变成最小的值
	a[maxIndex] = -1;
	*second_largest = a[0];

	for(int i = 1;i<n;i++)
	{
		if(*second_largest < a[i])
		{
			*second_largest = a[i];
		}
	}

}

/*
 *使用排序查找最大的值和第二大的值
 * */
void find_sort_tow_largest(int a[],int n,int *largest,int *second_largest)
{

	//1、初始化
	for(int i = 1;i<n;i++)
	{
		ifC语言与C++40 年的爱恨情仇!

对json的爱恨情仇

编程语言之间的“爱恨情仇”

python 第一天之高级语言与低级语言的爱恨情仇

C语言之数组指针指针数组

C语言之数组指针指针数组