C/C++基础查漏补缺(八)----------寒假学习笔记(八)

寒假C语言基础查漏补缺笔记(八)

本系列文章是基于自身的编程基础而编写的,其内容并非适用于所有人,请海涵~

不过内容应该包括了所有的考点、用法,初学C/C++的大学生或者noip入门级选手可以以此作为参考。

主要内容大致分为四个方面:计算机概念、简述编程中所需要的掌握的知识点(高亮显示即是知识点)、强调记忆C/C++基础语法中的不常用的特殊语法概念
以及

在学习过程中我的感悟和我从初中编程到现在所积累的经验(引用处即是)。

看完这系列文章,你可以快速地入门C/C++,而且我的文章也可成为你的复习笔记。

愿你的智慧加上我的,能完美解决你的问题。

需要下载Dev-C++ 5.11 可以关注微信公众号:MathsCode
回复:编译器,免费获得。

此文是基于中国大学MOOC北京大学郭炜老师的程序设计与算法(一)C语言程序设计(国家精品课程)而撰写的。

点击进入程序设计与算法(一)C语言程序设计——北京大学郭炜

非常厉害的老师!!!

看完觉得内容对您有帮助的,可以点个赞加个关注哦!

---------------------------笔记分割线------------------------------

终于到指针了好激动

指针的学习是C/C++基础中最复杂也是最抽象的一部分,而且在初始的基础阶段,指针的用处并不是很大,在普通的程序中仅仅可能只是一种能够辅助理解动态模拟过程的工具(简单点说就是想时针分针秒针一样的指向工具),而这里的指针不仅仅如此,它的功能在后来的数据结构与算法中才会渐渐体现出来,所以说,学好指针就是为学好数据结构打下坚实的基础

8.1 指针的基本概念和用法

8.1.1 指针的基本概念

每定义一个变量,系统都会开出相应的内存单元(字节)来存放这个变量,而指针的内容就代表着该变量存放的内存的开始地址。

通过指针,就能够对该指针指向的内存区域进行读写。

就类似于一个变量到宾馆开房间,电脑内存就是宾馆,指针就是该变量所开房间的房间号。

类型名 * 指针变量名
int * p      // p是一个指针,变量p的类型时 int *

初学者大多会被指针的复杂性搞晕了头
所以我在多次听课后并结合解题经验总结了理解的过程中要注意的两个点
①变量 p 是指针变量,类型是(int *),这是独立的一个变量类型,和整型变量类型之间毫无关系,只不过这个类型的变量p和整形变量是有关的,p是指向某一个整形变量。
②指针型变量p首先它也是一个变量,所以他本身也具有内存空间,然而它的作用是指向了一个整形变量。直白点来讲,指针变量p也在电脑这个宾馆开了个房间(房间号XXX),只不过它在这个房间打了个洞可以直接通到某一个整形变量的房间,所以要找那个整形变量就不需要知道他的房间号,可以直接从p的房间过去。

8.1.2 指针定义总结定义总结
8.1.3 指针用法
char ch = 'A';
char * pc = &ch;
// & :取地址运算符
// &x :变量x的地址
// 对于类型为T的变量x,&x表示变量x 的地址(即指向x的指针),&x的类型时T *
* pc = 'B'; //ch = 'B';
char ch2 = * pc; // ch2 = ch;
pc = & ch2;     //使得pc指针指向变量ch2;
*pc = 'b';   // ch2 = 'b';更改pc指向的变量后,改变*pc的值,ch的值则不会改变

8.2 指针的意义和互相赋值

8.2.1 指针的作用

有了指针,就有了自由访问内存空间的手段 ==> Freedom

不需要通过变量,就能对内存直接进行操作。通过指针,程序能访问的内存区域就不限于变量所占据的数据区域

举个直白的例子

int a; //定义了变量a
int * p; //定义了指针p
p = &a; //让p指向a,如下图所示


那么现在p存放就是a的地址,那我们就可对p本身来做文章,p++或者p–就会指向a地址的后一个地址或前一个地址,即是现在那个地址里面没有存放我们已定义的变量,或者存放的系统的文件。所以在某些病毒或者反病毒软件中,就要大大用到指针的用处。

8.2.1 指针的互相赋值

不同类型的指针,如果不经过强制类型转换,不能直接互相赋值
T 类型的变量的地址的类型是T *,所以需要对应类型的指针变量存储。

8.3 指针的运算

8.3.1 指针的运算

同类型的指针变量可以比大小、相加减。
对于两个T * 的指针p1,p2
p1 - p2 = (地址p1 - 地址 p2)/sizeof(T)。

指针变量可以加减一个整数,可以自增、自减
p + n :结果仍然是T *类型的指针,指向地址:地址p + n × sizeof(T)。

自增、自减(T * 类型指针p指向地址n)
p++、++p:p指向 n + sizeof(T)
p–、--p:p指向 n - sizeof(T)

指针可以用下标运算符‘[ ]’进行运算
T * p;
int n;

==> p[n] 等价于 *(p+n)

8.3.2 通过指针实现自由内存的访问

如何访问int 型变量a前面的那一个字节?

int a;
char * p = (char * ) &a; //&a 是 int * 类型
--p;
printf("%c",*p); //可能导致运行错误
* p ='A';      //可能会导致运行错误,因为a前面的那个字节可能不让访问。

8.4 指针作为函数参数

8.4.1 空指针

地址0不能访问。指向地址0的指针就是空指针

可以用“NULL”关键字对任何类型的指针进行赋值。NULL实际就是整数0,值为NULL的指针就是空指针

int * pn = NULL;
char * pc = NULL;
int * p2 = 0;
//当对指针赋值为0或者NULL后,就不可以执行如:* pn = 10; *pc = 'a';这类语句

指针可以作为条件表达式来使用。如果指针的值为NULL,则相当与为假,值不为NULL,就相当于为真。

8.4.2 指针作为函数参数
#include<bits/stdc++.h>
using namespace std;
void swap(int * p1, int * p2)
{
  int tmp = *p1;
  *p2 = *p1;
  *p2 = tmp;
}
int main()
{
  int n = 3, m = 4;
  swap(&n,&m);        //注意这里的实参是&m和&n,形参是p1,p2,实参、形参不理解可以看函数章节。
  cout<<n<<' '<<m<<endl;
  return 0;
}

这里就能实现将m、n的值进行交换。
不理解的请留言。

8.5 指针和数组

8.5.1 指针和数组

数组的名字是一个指针常量,指向数组的起始地址
如:T a[N];

a 的类型是T *

可以用 a 给一个T *类型的指针赋值

a 是编译时其值就确定了的常量,不能够对a进行赋值
所以说

void func(int p[])
{
  cout<<sizeof(p);
}

<==>

void func(int * p)
{
  cout<<sizeof(p);
}

两者的输出结果都是指针变量的字节数,一般是4 或者 8(取决于编译环境)。

可能有人要问为什么这里第一个sizeof§不能求出p数组的大小,即所含元素的个数?
如果在主程序中,或者在函数内部中定义的数组,是可以通过sizeof(数组名) / sizeof(类型)来求出数组元素的个数
但是,在调用函数时的形参,这里的p[]就是形参,是无法用sizeof(数组名) / sizeof(类型)知晓传递进函数的实参数组的数组元素的个数

接下来通过仔细阅读以下程序即注释,可以有助于你更快的理解指针和数组之间的关系。

#include<bits/stdc++.h>
using namespace std;
int main()
{
  int a[200];
  int * p;
  p = a;             //p指向数组a的起始位置,亦即p指向了a[0]
  * p = 10;          //a[0] = 10
  *(p+1) = 20;       //a[1] = 20
  p[0] = 30;         //p[i] 和 *(p+i)是等效的,使得a[0] = 30
  p[4] = 40;         //使得a[4] = 30
  for(int i = 0; i < 10; i++) 
      *(p+i) = i;     //对数组前10个元素赋值
   ++p;                //p指向a[1]
   cout<<p[0]<<endl;   //输出a[0]
   p = a+6;            //p指向a[6]
   cout<<*p<<endl;    //输出a[6] = 6;
   return 0;
}

那如果要将数组中的元素颠倒,即1 2 3 4 5 要变成 5 4 3 2 1,如何通过指针来完成呢?

#include<bits/stdc++.h>
using namespace std;
void reverse(int *p,int size)
{
    for(int i = 0; i < size/2; i++)
    {
        int tmp = p[i];
        p[i] = p[size-1-i];
        p[size-1-i] = tmp;
    }
}
int main()
{
   int a[5] = {1,2,3,4,5};
   reverse(a,sizeof(a)/sizeof(int));
   for(int i = 0;i < 5; i++)
   {
      cout<<*(a+i)<<',';
   }
   return 0;
}

讲函数的用法时,关于实参形参之间的数据传递关系,有过一个结论叫做:形参是实参的拷贝,形参改变不会影响实参的变化。但是有一个例外,当这个实参和形参是个数组的话,当形参数组在执行函数的过程中,值发生了改变,实参数组的值也会发生改变。
这个例外在这里便可以用指针的知识来解释。
其实并不是例外,它依旧不违反形参是实参的拷贝。因为实参,形参都是指针,这里形参拷贝的是实参数组的地址,所以函数在执行中通过形参直接访问的实参的数组,将其改变,所以便是有了数组例外的这个说法。

指针这一章难点、复杂点还是比较多的,但是一般情况下编写程序的时候,最初级阶段是用不到指针,到了后期高级数据结构中会用到指针,那才是指针大显身手的地方。

---------------------------笔记分割线------------------------------
码字不易,喜欢这篇文章的话,关注我的CSDN吧,
我的高中数理化学习干货
Noip竞赛经验
自招笔试小窍门、面试小套路
大学理工科学习规划
均在我的公众号中
扫码关注吧!

结语

感谢你的耐心阅读,码字不易,阅读不易。

愿你的努力加上我的,能完美解决你的问题。

居家防控疫情,也不能放松了学习,可以充分利用互联网线上学习的功能,让自己过一个充实的寒假。

武汉加油,中国加油。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值