C语言指针部分教学总结

By | 06月10日
Advertisement

C语言作为一门学科基础课程,几乎覆盖了高校的所有理工科专业。开设该课程的目的旨在培养学生运用计算机解决问题的基本能力,为后续的工作和学习打下基础。而在C语言的教学内容中,指针部分是必不可少的教学内容。考虑到同学们对指针理解和掌握存在一定的难度,因此,将指针的相关知识点贯穿在整个C语言的教学中,将有助于同学们更快的理解和掌握指针。

1、指针与地址

C语言中,指针就是地址。如何让同学正确认识地址,是能否正确理解和掌握指针的关键。我们从课程的第一章开始,就一直学生反复地介绍地址,为后续知识点的学习奠定必要的基础。涉及的主要内容有以下三点:

1.1变量的地址

在第一章让同学们熟悉C语言的编程环境时,同学们容易出现如下的错误:

 int a;  scanf(“%d”,&a);  printf(“%dn”, &a);

在该程序中,输入的并不是变量a的值,而是一个比较大的数。此时,需要给学生解释,&a是变量a在内存中的存储地址,并不是a的值。

1.2 指针与一维数组

在介绍一维数组中,教学时需要从变量的教学内容过渡过来。普通的变量是申请一个存储单元,而数组是申请一块连续的存储空间。对普通变量a而言,空间的存储地址为&a,而对数组而言,存储空间的首地址则是数组名。如果定义了一维数组inta[10]后,介绍一维数组时,需要讲清楚 a+9是第10个元素的存储地址,而不是地址的简单相加。访问第i个元素可以用a[i],也可以用*(a+i)。如果在数组中能讲清楚这一点,就可以在讲解返回指针的函数中进一步介绍。例如,要求用返回指针的函数编写程序,判断某一输入的元素是某数组中的第几个元素,可以编写如下的程序:

#include<stdio.h> int *find(intarr[10], int num) {        int i,*p;        for(i=0,p=arr;i<10;i++,p++){               if(*p==num)                      return p;        }        return NULL; }   int main() {        int a[10]={1,2,3,4,5,6,7,8,9,10};        int num;        int *findAddress;        scanf("%d",&num);        findAddress=find(a,num);          if(findAddress!=NULL)               printf("%d-th element. n",findAddress-a+1);        else               printf("not found");          return 0; }

1.3 指针与函数

函数是另一个涉及地址的知识点。当定义函数时,编译好的函数在存储空间中同样占据连续的存储空间,而该存储空间的首地址即为函数名称。在讲授函数时,可以通过下面的程序,简单地演示函数的这一特性。

#include<stdio.h> int max(int a, intb){        return a>b?a:b; }   int main(){        printf("the address of the functionis %d.n",max);        return 0; }

如果介绍函数时,对这个知识点进行介绍,在指针部分介绍指向函数的指针就可以让同学们理解为什么可以把指针和函数关联起来。

2、指针与字符串

字符串是一个特殊的数组,与一般的数组相比,有两个特性:(1)数组中元素的类型是字符;(2)字符串与一般的数组相比,更具有整体意义。当指针与字符串结合时,与数值型数组相比,字符串数组要注意以下几点:

(1)定义指向字符的指针时,可以直接赋值,而指向数值型的数组不可以。例如,可以定义char *sp=”I am a student”,但定义int *a={1,2,3,4,5}就是错误的用法。这是因为C语言编译系统将”I am astudent”看成是字符串常量,在存储空间中存储这个常量,并把存储地址赋给指针变量sp。

(2)注意字符串与字符指针的区别

char *temp, str1[]=”I am a student”;

strcpy(temp, str1); 是错误的

3、指针与二维数组

许多高校在介绍指针部分时,通常略去指针在二维数组中的应用,原因在于无法恰当地让同学们理解二维数组中行地址和列地址的关系。本部分从一维数组的角度出发,对二维数组中的指针进行详细介绍。

讲授二维数组时,应从一维数组的教学内容进行过渡,因为二维数组是一个一维数组,一维数组的每一个元素都是一个一维数组。所以说,二维数组是一维数组的一维数组。以数组int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12}为例,它实际是由三个元素a[0]、a[1]和a[2]组成的,因此如果a指向二维数组存储空间的首地址,a+1则指向下一个元素的存储地址,即a[1]的存储地址;同样,a+2指向a[2]的存储地址。因此,a、a+1、a+2就是教材上所讲的行地址。而对a[0]、a[1]和a[2]三个元素而言,每一个元素都是一个一维数组。即,

a[0]={1,2,3,4}

a[1]={5,6,7,8}

a[2]={9,10,11,12}

在这三个元素中,a[0]、a[1]和a[2]是三个一维数组的数组名,因此,第一个一维数组的四个元素分别为a[0][0]、a[0][1]、a[0][2]和a[0][3]。而对这个一维数组来讲,数组名a[0]即为首元素的存储地址,a[0]+1、a[0]+2、a[0]+3则是后三个元素的存储地址。因此a[0]、a[1]、a[2]和a[3]即为教材上所讲的列地址。基于这点考虑,我们不建议介绍行地址和列地址时,采用*(*(a+i)+j)的方式进行,可以采用如下的方式进行:

for(i=0;i<3;i++){

for(j=0;j<4;j++)

printf(“%d”,*(a[i]+j));

printf(“n”);

}

如果利用指针来处理,要正确理解指针与地址的关系。如果定义指针int *ps,而用ps=a去让指针与二维数组关联,会产生类型不相符的错误。此时,要注意引导学生理解指针指向的内容。对指针ps而言,它指向的是一个整型变量,而对二维数组而言,指向的内容却不是一个整型变量,而是一个整型数组。因此,如果要采用指针去处理,应采用指向一维数组的指针int (*ps)[4],此时令ps=a后,可以采用如下的方式输出整个数组的元素:

for(i=0;i<3;i++){

for(j=0;j<4;j++)

printf(“%d”,*(*(p+i)+j));

printf(“n”);

}

这里采用的*(p+i),只是为了使形式上统一,可以将其替换为p[i],以便于学生加深理解。

4、指针与指针数组

在指针部分,指针数组也是一个非常重要的概念,需要同学们理解。稍有不慎,就容易和指向一维数组的指针混淆。因此,要及时地对相关定义进行总结,定义指向一维数组的指针定义为int (*p)[4],代表指向含有4个元素的一维数组的指针,而int*p[4],则由于[]运算的优先级高于*运算,因此,从本质上讲它是一个数组,数组中的元素是指向整数的指针变量。下面我们通过对字符串排序加深对指向一维数组的指针和指针数组加深理解。

从主函数输入十个不等长的字符串,编写函数,对这些串进行排序,在主调函数中输出排好序的串。

对于本程序,可以通过以下三种不同的方式加以实现。通过这三个小函数,将有助于同学们进一步理解指针、指向数组的指针以及指针数组。

#include <stdio.h>   #include <string.h>   #define N 5   void sort1(char (*str)[10]){     int i,j;       char temp[10];          for(i=0;i<N;i++) {           for(j=i+1;j<N;j++){               if(strcmp(str[i],str[j])>0){                   strcpy(temp,str[i]);                   strcpy(str[i],str[j]);                   strcpy(str[j],temp);               }           }       }   }     void sort2(char *ps[N]){      int i,j;      char *temp;            for(i=0;i<N;i++){          for(j=i+1;j<N;j++){              if(strcmp(ps[i],ps[j])>0){                 temp=ps[i]; ps[i]=ps[j]; ps[j]=temp;             }          }  }  }   void sort3(char *ps[N]){      int i,j;      char temp[10];           for(i=0;i<N;i++){         for(j=i+1;j<N;j++){              if(strcmp(ps[i],ps[j])>0){                  strcpy(temp,ps[i]);                 strcpy(ps[i],ps[j]);                  strcpy(ps[j],temp);              }          }      } }   int main() {   char str[N][10];   char *ps[N];      int i;              for(i=0;i<N;i++)  {         gets(str[i]);          ps[i]=str[i]; }           sort1(str); //基于指向一维数组的指针实现     sort2(ps); //基于指针数组实现     sort3(ps); //基于指针数组实现          return 0;   }

在上述例子中,如果通过键盘输入的五个字符串分别为str[0]=”Jinan”、str[1]=”Qingdao”、str[2]=”Yantai”、str[3]=”Weifang”、str[4]=”Weihai”,则函数sort1、sort2和sort3函数排序原理如下。

(1)sort1函数。是通过指向一维数组的指针实现的,因此,传递的参数str[0]、str[1]、…、str[N]从本质上讲,都是指向字符的指针,即字符串。因此,sort1函数的本质是对字符串进行排序,排序的结果如下:

C语言指针部分教学总结

图1 sort1函数的排序结果

(2)sort2函数。通过指针数组进行排序,传递的参数中,ps[0]、ps[1]、…、ps[N]是相应的字符串的名称,也就是相应的地址。由于sort2函数是对指针数组中的地址进行了交换,因此str[0]、str[1]、…、str[N]中对应的字符串没有发生改变,即通过输入str无法得到排序后的结果,而通过指针数组ps[0]、ps[1]、…ps[N]可以得到正确的结果,排序结果如下:

C语言指针部分教学总结

图2 sort2函数的排序结果

(3)与sort2函数不同的是,sort3函数是对地址对应的字符串进行了交换,因此,ps[i]与str[i]的对应关系没有改变,而str[i]中存储的字符串发生了改变。所以,sort3函数的排序结果如下图所示:

C语言指针部分教学总结

图3 sort3的排序结果

如果授课过程中可以从这个角度引导同学们加深对指针的理解,将有助于同学们正确的认识并理解指针、数组以及指针数组。

5、结束语

指针部分是C语言教学过程中的重点和难点,本文通过实例教学,介绍了如何在授课过程中介绍了指针与地址的关系,如何讲授二维数组中的指针,指向一维数组的指针以及指针数组等内容。

以上是笔者对指针部分在授课过程中的经验总结,由于笔者水平有限,期待更精彩的教学案例设计,以期促进C语言的教学。

参考文献

[1] 谭浩强.C程序设计[M].北京:清华大学出版社,2002.

[2] 宋丽华,雷鹏,张小峰.C语言程序设计[M].北京:清华大学出版社,2014.

[3] 赵忠孝,杨亚蕾.对C 语言指针教学问题的探究[J].计算机教育,19:72-74,2009.

[4] 于福生,刘玉铭,王加银.C 语言课程中指针内容体系设置的改革尝试[J].计算机教育,4:22-24,2013.

[5] 李俊萩,赵家刚,张晴晖.C 语言指针教学中的知识点分析与总结[J].计算机教育,8:55-61,2011.

Similar Posts:

  • C语言指针与数组

    C语言指针与数组 数组的下标应该从0还是1开始? 我提议的妥协方案是0.5,可惜他们未予认真考虑便一口回绝 -- Stan Kelly-Bootle 1. 数组并非指针 为什么很多人会认为指针和数组始终应该可以互换的呢? 因为对数组的引用总是可以写成对指针的引用,而且确实存在一种指针和数组的定义完全相同的上下文环境, 不幸的是,这只是数组的一种极为普通的用法,并非所用情况下都是如此. 2. 什么是声明,什么是定义 C语言中对象必须有且只有一个定义,但它可以有多个extern声明. 定义:只能出现

  • [转]C语言指针学习经验总结浅谈

    指针是C语言的难点和重点,但指针也是C语言的灵魂 . 这篇C语言指针学习经验总结主要是我入职以来学习C指针过程中的点滴记录.文档里面就不重复书上说得很清楚的概念性东西,只把一些说得不清楚或理解起来比较费解的东西做一下讲解,希望能达到以下三个目的 1.通过写这些东西,把我脑袋中关于C的模糊的知识清晰化. 2.给初转C的同事们一点提示和帮助. 3.也希望各位前辈检查一下文档中是否有理解偏差的地方. 1 指针的概念分解 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址. 要搞清一个指针

  • Swift与C语言指针友好合作

    翻译:老码团队翻译组-Relly 校对:老码团队翻译组-Tyrion 本页包含内容: 用以输入/输出的参数指针 作为数组使用的参数指针 用作字符串参数的指针 指针参数转换的安全性 Objective-C和C的API常常会需要用到指针.Swift中的数据类型都原生支持基于指针的Cocoa API,不仅如此,Swift会自动处理部分最常用的将指针作为参数传递的情况.这篇文章中,我们将着眼于在Swift中让C语言指针与变量.数组和字符串共同工作. 用以输入/输出的参数指针 C和Objective-C并

  • C语言指针操作

    欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/pointer-manipulation.html 原创:C语言指针操作 作者:MilkCu 摘要:指针是C语言的核心,也是一个普通变量,存储的是内存中的地址.在存储空间的分配中,一种常遵循的理念是,由用户管理存储空间以及与存储空间相关的实际的数据结构,而数据结构自身只用于维护数据内部变量的存储空间的分配.C语言使用基于堆的内存分配,通常也

  • C语言指针-链表逆转

    昨晚看到庭波老师的日志说要实现链表逆转,点进去看了下.庭波老师的算法是把链表的数据读出来,用数组存起来,然后再逆向放到链表里.我觉得这个做法太暴力了,费内存还费时间.至少来说,建立一个数组(要都是链表不小的话)就耗掉好多内存,把数据倒腾来倒腾去,也会费掉好多时间. 出于ACMer的直觉,我提出可以直接用指针实现,更加体现C语言指针的特性,也能省掉内存和时间.庭波老师可能最近讲了数组吧,一直掐着数组不放,说要建一个指针数组,然后给每个链表节点一个指针,然后再通过修改p->next来实现逆转. 其实

  • C语言指针类型、指针大小、指针所指元素大小、指针加减运算

    摘要:在C语言编程的过程中,我们经常用到多维数组,指针的加减运算等等.如果我们想把一个二维数组传递给一个函数,为什么不能用"a[][]"这样的形参模式?而把一维数组传递给函数可以用int a[]这样的形式?内核代码中,我们常常能看到,有两个page类型的结果体指针pagea和pageb,那么pageb-pagea数值上等于多少?是地址差还是index的差值?本文主要为你解答这些问题. 本文来源:C语言指针类型.指针大小.指针所指元素大小.指针加减运算 http://blog.csdn.

  • C语言指针系列1——指针基本概念

    C语言指针系列1--指针基本概念 可以说,指针是现代编程语言的一个基本且重要的概念和知识点.对于现在流行的计算机语言,只有理解了指针的概念和熟练运用后,才能学好它(包括C/C++.JAVA.C#等).虽然JAVA中并没有指针这个名词,但它实际上是存在指针的. 废话少说,相信大多数看官都是想直接看一看C语言的指针是什么了.首先看下面的代码: int i=1; 这句代码声明了一个整型变量,并且赋值为1.其内存快照如下(假设int型变量点4个字节) 下面声明一个指针: int *p; 这是一个声明指针

  • C语言指针系列四——指针与函数

    C语言指针系列四--指针与函数 之前说指针是变量的地址,不得不承认,这也是一种习惯上的说法--因为它不够全面,但不能说这种说法是错的,因为还有一种特殊的指针--函数指针. 函数也是存在于内存中的,函数指针指向的是函数在内存中的首(开始)地址.首先来了解一下怎么使用函数指针: #include<stdio.h> double Integrate(double (*f)(double), double a, doubleb) { //这个函数用于对任意f函数计算[a,b]上的积分 //f是一个指向

  • C语言指针详解(一)

    C语言指针详解(一) 指针是什么 指针就是变量,真有内存空间,用来保存内存地址. 指针指向某个变量,就是把某个变量地址赋给指针. 指针和内存 C语言在编译之后,会以三种形式使用内存 静态/全局内存 静态声明的变量分配在这里,全局变量也使用这部分内存.这些变量在程序开始运行时分配,知道程序终止才消失.所有函数都能访问全局变量,静态变量的作用域则局限在定义它们的函数内部. 自动内存 这些变量在函数内部声明,并且在函数调用时才创建.它们的作用域在函数内部,并且生命周期限制在函数的执行时间内. 动态内存

  • c语言—成也指针,败也指针--教c语言指针有感

    最近教学生c语言指针部分,其实自己是一个指针的坚决反对者,觉得还是java里面的应有比较好一点不容易出问题,想出题目这句话还是上课的时候看见我的学生一脸茫然的看着我的时候,我觉得我是用尽我的全力去诠释这指针的概念给我的学生,自认为讲得还算比较清楚(虽然最近真的有点怀疑自己对教师这个职业的还能坚持多久),但是学生还是觉得听的茫然,今天有个学生问我说指针跟前面c语言讲的没有联系问我为什么要学指针,我觉得这个问题不是困扰他一个学生,而是困扰了许许多多c语言的学习者, 所以引发我这个c语言指针的反对者也

Tags: