C语言程序设计(谭浩强版本)-考研版注意事项-适合考研和C语言入门小白食用

文章目录

    • C语言程序设计(谭浩强版本)-考研版注意事项-适合考研和C语言入门小白食用
  • 前言
  • 一、指针是什么?其实指针=地址
  • 二、指针变量
  • 三、指针变量作为函数参数 -值传递和地址传递区分
    • 何为值传递? 先给大家分析一下值传递:
    • 何为地址传递?
  • 四、 通过指针引用数组
  • 五、自增自减运算符区分 以 ++n和n++示例
    • 一、基础变量类型的自增自减
      • 示例1:单独使用
      • 示例2:用在赋值表达式当中
      • 示例3:用在条件循环表达式当中
    • 二.指针类型的自增自减的使用
      • 示例1:用在*运算符中
  • 总结


前言

计算机考研人数的剧烈增多,博主也是考研er大军中的一员,自命题的C语言考试正在逐年转为统考408,所以大家需要抓紧时机,积极备考!趁着初试结束,打算每周更新一下C语言程序设计(谭浩强版)这本小红书,结合着小红书和自己的经验,写一下其中有比较多的细节和干货以及挖坑的注意事项,欢迎大家收看,如有错误的地方,请客官大人及时批评指正~


一、指针是什么?其实指针=地址

首先我们要明确,C语言所说的指针,就是地址,提到指针,它就是地址!!,两者完全相同!
至于为什么地址也叫做指针,请看下面的解释:
理解指针,首先要理解 变量变量的存储单元,以及**地址(指针)**的关系:

我这里的展示的是一段内存用户数据区,其中2000-2004这一个区域叫做存储单元,当然你可以把2004-2008这个也叫做存储单元,因为我们没有给这两部分取名字,所以叫谁存储单元都是正确的。

那么现在我们开始创建一个变量:

int a;//这里的a是一个int型的变量,占4个字节

当我们创建一个变量的时候,计算机会自动帮我们寻找一个4字节的存储单元的空间,假设计算机此时正好寻找了2000-2004这一区域(实际上是随机寻找的),那么2000-2004这一存储单元叫做变量a;
那么2000-2004这一块区域,叫做变量a的存储单元首地址2000叫做变量a的存储单元的地址

二、指针变量

刚刚介绍完毕上面三者的关系,我们知道,变量是用来存储对应的数据的,例如int类型的变量只能存储int类型的数据,float类型变量只能存储float类型数据…
那么现在C语言有一种能存储地址的变量(例如有一种专门存储变量a的存储单元首地址的变量),我们是不是叫做地址变量呢?emmm当然不是,因为c语言已经规定了这种变量叫做指针变量,而指针变量存储的内容,就是地址,(而且一定是地址,不能是其他数据),由于叫做指针变量,所以它存储的内容,人们也习惯叫做指针。
所以指针=地址,只不过是不同的称呼罢了。
所以P222页有一段代码是一个经典的错误:
因为C语言把这个整数100它只会当作int型数据去处理,而不是你自以为的把100认为是地址;
程序是不能用一个数值代表地址,对于地址只能用& 得到并赋值给一个指针变量

int *pointer_1;
* pointer_1=100;//这个赋值是错误的
int a,*pointer_1;
* pointer_1=&a;//这个赋值是正确的

三、指针变量作为函数参数 -值传递和地址传递区分

本书对于函数的参数传递方式一共就介绍了两种:值传递和地址传递
P224页
从此页开始介绍指针变量作为函数的参数的情况,在这之前,本书的参数传递方式是值传递,也就是参数不涉及到所谓的指针类型,一般函数参数都是变量:

void add(int a,int b);//参数a b都是int类型的变量,不是指针类型,判断为值传递;

何为值传递? 先给大家分析一下值传递:

请大家看一下代码:

1.	void swap1(int x,int y)
2.	{
3.		int temp;
4.		temp = x;
5.		x = y;
6.		y = temp;
7.		printf("x = %d,y = %d\n",x,y);	
8.	}
9.	int main() 
10.	{
11.		int a = 12,b = 24;
12.    swap1(a,b); // 值传递 
13.    printf("a = %d b = %d",a,b);
14.	}


结果如图所示:

分析:

首选我们都知道main实际上也是一个函数,它的作用范围是 第10行-第14行
swap1也是一个函数,它的作用范围是1-8行
main函数中的变量与swap函数区域中的变量互不冲突的:
程序未执行前:

当程序执行到第12行时候:
main函数中的变量a把12这个int型数据赋值给swa1中的变量x(变量b对y也是同理),之后后续的在swap1函数中的操作,全是针对swap1函数中的变量x和变量y进行的,与Main函数中的变量a和p没有关系了! ,a和b仅仅起到了赋值的作用!! ! !


所以swap1中的x和y的交换,实际上是swap1函数中的x和y交换,与main函数中的变量a和b没有关系,而且我们是在main函数中的是 printf(“a = %d b = %d”,a,b); ,当然要输出的是main函数中的变量a和b,

何为地址传递?

在前面一和二章节的基础之上,我们分析下面的例子:

1.void swap2(int* x,int* y)
2.{
3.	int temp;
4.	temp = *x;
5.	*x = *y;
6.	*y = temp;
7.	printf("x = %d y = %d\n",*x,*y);
8.}
9.int main(int argc, char *argv[]) 
10.{
11.	int a = 12,b = 24;
12.	swap2(&a,&b); //地址传递
13.	printf("a = %d b = %d",a,b); 
14.}


**

1.程序未执行前的状态:

这一次我们标注好了Main函数中变量a和变量b的地址,(下面那个打错了,应该是swap2的函数作用区域

.
2. 当程序执行到第12行时候:由于&a和&b代表的是地址,即参数是地址,程序执行的是地址传递的方式,地址传递不同于值传递,此刻的变量a和变量b会把自己的地址传递给变量x和变量y:

3.那么后续中对swap2函数中的操作:

1.void swap2(int* x,int* y)
2.{
3.	int temp;
4.	temp = *x;// *是代表把指针变量x所存储地址(x当中存储的是2000  也就是main函数中变量a的地址) 的对应内容(地址2000(即变量a的地址)对应的内容是12)交给temp;
5.	*x = *y;//   把指针变量y存储的地址   对应的内容 交给  指针变量x存储的地址  对应的空间
6.	*y = temp;//同上理
7.	printf("x = %d y = %d\n",*x,*y);
8.}

这样实际上在swap2函数中对地址的操作,实际上是在对main函数中的变量内容进行操作,所以最后的结果为:

四、 通过指针引用数组

这一章节,介绍新的引用数组元素的方法:指针法
引用数组元素一般有两种方法:1.下标法 2.指针法;
看下面一段代码:

int a[7]={1,2,3,4,5,6,7};//定义一个数组,名字为a;
int *p;
p=&a[0];//&表示把取首地址的值,这里把a【0】的首地址2000取了出来,交给指针变量P存储

数组空间如下图所示:

从图中我们可以看出,a[0]的首地址为2000;指针变量p的内容也是2000,C语言规定,数组名不代表整个数组,而是数组名会代表数组首元素的地址,即数组名字a是一个指针型的常量,这里数组的首元素为a[0],首元素的地址为2000,所以单独拿出来a这个名字,就代表2000这个地址:
所以P=&a[0] 和p=a是等价的:
由于数组名字a是个指针型的常量(即地址的值固定)不能出现对它进行赋值的操作:
这就好比一个常量2, 你还要进行2=2+1的操作;下面的操作全是语法错误;

数组名可以赋值给别的变量,但是自己不能作为被赋值的变量,因为它是常量常量!指针型常量!!!!

a++;//错误 a++等价于a=a+1;
a=a+1;//错误
p=a++;//错误  等价于p=a;a=a+1;

p=a,程序解释为把数组a的首元素的地址赋值给指针变量P,和p=&a[0]的解释是一个道理,所以两者是等价的;
总结一下,下面四个是等价的:

书中的等价
一维数组int *p=&a[0]; 和int *p =a; 和 int *p; p=&a[0]和int *p; p=a;

在指针已经指向一个元素的前提之下:
我这里P是指向a【0】的,因为P存储的地址和a【0】的相同。
规定:
P+1指向的是数组的下一个元素;也就是p存储的地址本来是和a【0】地址相同即2000,p+1之后,p存储的地址会和a【1】的地址相同,即2004,不难看出,P+1 实际上是增加了4个字节(2004-2000),这是由于P的基类型所决定的,忘记基类型是什么的可以去翻书看一下~
同理,P-1指向的是数组的上一个元素;
所以a[i]的地址和a+i表示的地址是相同的;
所以指针法表示数组:* (a+i)和 *(p+i)表示的是a[i];
第二个等价:

书中的等价
一维数组int *p=&a[0]; 和int *p =a; 和 int *p; p=&a[0]和int *p; p=a;
一维数组*(a+i)等价于a[i] ;因为a[i]和a+i的地址是相同的

五、自增自减运算符区分 以 ++n和n++示例

一、基础变量类型的自增自减

自增自减运算符,当我们去查看书或者在网上搜寻区别的时候,最多的回答就是:
n++是先赋值,n再加1
++n是n先加1,再去赋值

这样的解释把,其实是很正确的,但是,对于新手小白却不友好,因为说出这样话的人,已经能够深刻的理解到,他们能够区分出来两者到底不同于什么地方,以至于传授经验的时候,不容易被小白同学们消化,下面我会多举例子来验证一下两者的区别:

示例1:单独使用

int main()
{
	int a=0,b=0;
	a++;
	++b;
	cout<<"a的值为:"a<<"b的值为:"<<b<<endl;
}

运行结果:
a=1;b=1;

这种情况下的的a++和b++,当程序执行到a++的时候,执行的操作就是对a的值进行+1;也就是a=1;
同样的情况下++b也是如此,当执行到++b的时候,同样程序进行的操作直接对b进行+1,也就是b=1;
那么这样看过来,好像a++和b++的结果也没啥区别?,是的,结果确实是没啥区别,最后a和b的值都为1;

示例2:用在赋值表达式当中

int main(){
	int a=0,b=0,num_1,num_2;
	num_1=a++;
	num_2=++b;
	printf("%d,%d,%d,%d",num_1,num_2,a,b);
}

运行结果:
num_1=0;num_2=1;a=1;b=1;

那么这一次,a++和++b不像示例1作为一个单独的运算出现,而是参与到了赋值运算当中,将值需要赋值给num_1和num_2;
这个时候我们可以看出来a++和++b之间的区别了,对它进行详细分析:
当程序执行num_1=a++的时候:
实际上按照运算符的优先级的基础上,程序会对于num_1=a++,这一段代码,进行分两步进行:
1.由于a++的特性是先赋值再运算,刚开始时候a=0,所以会把num_1通过变量a的值,赋值为0;
2.然后在对a进行+1运算,这个时候a+1,a从0->1;
当程序执行num_2=++b的时候:
实际上按照运算符的优先级的基础上,程序会对于num_2=++b,这一段代码,进行分两步进行:
1.由于++b的特性是先运算再赋值,,刚开始的时候程序读到这一段,会首选对num_2=++b的变量b进行+1,也就是b=1;
2.然后b的值现在为1,再对num_2进行赋值操作,这个时候num_2就获取到了1这个值,程序结束.

示例3:用在条件循环表达式当中

int main(){
	int a=1;
	while(a++<5);
	printf("%d",a);//输出a的值
	int b=1while(++b<5);
	printf("%d",b);//输出b的值
	
}

运行结果:
a=6;b=5

这里自增运算符不仅可以用到赋值表达式当中,也可以用到条件表达式当中;
我们应该有这举一反三的思想,既然在赋值表达式里面a++应该是先赋值在+1,那么在条件循环表达式当中,应该是先执行循环条件然后再+1,下面请看分析:
例子:while(a++<5);其中a++<5称为循环条件;
程序执行过程依分为两步走:

  1.  a=1,1<5 while表达式为T ;
    
  2.  a+1;即a=2;
    

然后去执行while循环体中的内容;我们这里没有内容,所以就会再一次进行判断:

  1.  此时a=2,2<5;while表达式为T;
    
  2.  		a+1;即a=3;  ...
    

然后去执行while循环体中的内容;我们这里没有内容,所以就会再一次进行判断:
当执行到:

  1.  a=5,5<5;while表达式为F,
    
  2.  a+1	;a=6;
    

这个时候由于while为F,程序结束,所以a=6;
同理,++b<5的情况完全是上面的情况反着来,程序会对b先+1,然后在执行判断条件b<5;最后结束循环的时候,b=5;

二.指针类型的自增自减的使用

关于指针类型的自增自减,其实和基本变量类型的处理方式差不多:
无论a++是在哪一个表达式当中,记住要先****,在a+1;
++a则是先a+1,在进行****;

示例1:用在*运算符中

int main(){
	char *s="abcdef";
	char *p=s;
	printf("%c",*p++);
	printf("%c",*++p);
}

运行结果;
a
c
这里p指向的是字符串中字符a的首地址;
printf("%c",p++);
1.先printf("%c",p);由于p指向的是字符a,所以打印出来了a
2.p+1,此时p会指向b;
printf("%c",
++p);
1.先p+1,此时p从指向b变为指向字符c;
2…先printf("%c",p);由于p指向的是字符c,所以打印出来了c

总结

由于我只是挑出来一些重点和易错易混淆的知识点去讲解,并不是全书的内容哦,所以想要真正的去学号C语言的入门,还是需要结合那个小红书(谭浩强版本C语言)踏踏实实的去看,不建议大家抱着一个C primer 那个大厚书去学习,那个是用来随时查询某些方法或者知识点用的,入门的话还是选个讲解简单通透的书就可以,当你对C语言有了一定基础,再去看那本大厚书,来看由于我还要准备刷题备战等原因,更新得会慢一些,如果对读者朋友们有所帮助,不要忘记给个赞哦~你的点赞是我更新的最大动力!祝愿大家都顺利上岸!

更多推荐

C语言程序设计 详细注意事项