C语言教学指导 3-结构体和指针

  • 内容
  • 评论
  • 相关

第八章 实战经验

  1. 在使用指针时会发生视图引用未初始化指针的错误

例如:

int *p;

*p = 15;

因为指针p在声明时未进行初始化,指向的是一个随机的地址。它可能指向系统栈、全局变量、程序代码区等。那么在执行*p = 12时,程序不加辨别的视图在指针p指向的位置写入12,这时是很有可能出问题的,程序很有可能崩溃。

正确的应该是:

int *p,a=3;

p = &a;  //进行初始化,存放变量a的地址

*p = 1;

  1. 在使用指针变量的时候,试图将一个整数赋给指针变量,这样做是错误的

例如:

*p = 123;

因为系统根本无法辨别它是地址,表面上看123就是一个整数,而整数有它对应的数据类型,要赋给整型的变量而不能直接赋给指针变量,这样是非法的。

正确的应该是:

int*p,a=3;

p = &a;

  1. 初学容易误以为一个变量名加上*号这个整体代表指针变量。

例如:

int a = 1;

int *p;  //误以为*p这个整体代表指针变量

*p = &a;

在声明变量p时,前面加*,意思是p一个指针变量,这个指针变量的名字为p,并不是*p合起来的整体代表指针变量。*是指针运算符,*p代表指针变量所指向的对象。

正确的应该是:

int a= 1;

int *p;

p = &a;

  1. 将一个变量的地址赋给了一个与该变量所属类型不同的指针引发的错误。

例如:

double a = 10;

int *p;

p = &a;

指针变量所指向的类型与变量的类型不相同。

正确的应该是:

double a = 10;

double *p;

p = &a;

  1. 在使用指针时,容易发生指针内存分配未成功,却使用了它的错误

例如:

//下面代码是一个创建一个带附加头节点的链表的错误示例。

struct node  //节点结构

{

char data;   //数据域,存放字符

struct node *next;  //指针域,指向后继节点

};

struct node* CreateLinklist(struct node *head,charstr[]) //用来创建链表的函数

{

struct node *p;   //辅助指针p

intlen = strlen(str);

head = (struct node*)malloc(sizeof(struct node)); //为其分配内存

head->next = NULL;

for(inti = 0; i<len; i++)

{

p->data = str[i];

p->next = NULL;

p->next = head->next;

head->next = p;

}

return head;

}

错误之处在于当要创建一个新的链表的节点的时候,并没有像给附加头结点head那样为指针变量p分配内存就使用了指针变量p,发生内存错误是件麻烦的事情,因为编译器不能自动发现这些错误,通常是程序运行的时候才能捕捉到,而且用户还不容易发现自己犯了这样的错误,因此使用指针的时候一定要格外注意这一点。

正确的应该是:

struct node* CreateLinklist(struct node *head,charstr[]) //用来创建链表的函数

{

struct node *p;   //辅助指针p

intlen = strlen(str);

head = (struct node*)malloc(sizeof(struct node));

head->next = NULL;

for(inti = 0; i<len; i++)

{

p = (struct node*)malloc(sizeof(struct node)); //使用malloc为p开辟内存。

p->data = str[i];

p->next = NULL;

p->next = head->next;

head->next = p;

}

return head;

}

  1. 当指针指向数组的时候,可以对指针进行加、减运算。但并不是任意两个指针都能进行指针运算,两个指针相加后可能会超过内存的最大值或指向无意义的某个地址,没有什么意义,当指针指向数组的时候,加法运算可以使指针指向数组中的某个元素,减法运算可以求出数组中两个元素间的相对距离。
  2. 用指针访问数组可能出现越界问题。

例如:

int a[]={1,2,3,4,5};

int *point;

point = a;

printf("%d\n",*(point+10));

数组的大小为5,加上10越界

正确的应该是:

int a[]={1,2,3,4,5};

int *point;

point = a;

for(inti = 0; i< 5; i++)

{

printf("%d ",*(point+i));

}

第八章 实战练习

  1. 定义一个整型变量并定义一个整型指针变量指向它,输出通过指针变量。
  2. 定义一整型指针变量,输出指针变量所占用的字节数。
  3. 输入a,b,c三个整数,使用指针方法使其从大到小排序并输出,输出通过指针变量。
  4. 定义一个长度为10的整形数组并赋初始值,分别用指针和数组名访问数组中的元素。
  5. 定义一个整型的二维数组并赋初始值,用指针访问二维数组中的元素,并求出二维数字中元素的最大值和最小值。
  6. 编写一程序,使用指针引用字符串”I love C”,并求串长。
  7. 编写一程序,将两个字符串s1=”world”,s2=”hello ”.使用指针将两个字符串连接起来,s2接在s1的后面。
  8. 编写一程序,输入两个字符串,自行编写一个字符串比较函数,并使用字符指针变量来比较两个字符串s1,s2的大小。规定如果字符串1大于字符串2,返回值为1;字符串1小于字符串2,返回值为-1;字符串1等于字符串2,返回值为0。
  9. 编写一个函数fun,实现输出”hello world”的功能,在主函数使用函数指针变量调用fun函数实现输出”hello world”。
  10. 定义一个指向整型变量的指针数组,并用若干整数对其进行初始化,即使数组中的指针变量指向各个数字,然后用冒泡排序法来使这些数字从大到小排序,要求通过改变指针的指向来实现排序。
  11. 定义一个int型指针,并学习使用malloc为其开辟动态内存。
  12. 写一个最简单的链表。

 

第九章 实战经验

  1. 如果要使用结构体数组的某一成员要先用[]再引用成员。

例如:

要使用第三个学生的年龄:

stu.age[2]  非法的

stu[2].age  正确

  1. 使用结构体数组对成员输入时若成员为字符数组,输入时做字符串输入,则不需要加取地址符直接使用数组名。

例如:

对于第一个学生进行输入信息:

scanf(“%s”,&stu[0].name);  非法的

scanf(“%s”,stu[0].name);    正确

  1. 常见中英文符号错误

例如:

struct Student

{

char name[20];

int age;

}stu[10];非法的

struct Student

{

char name[20];

int age;

}stu[10];               正确

  1. 结构体也是一种数据类型,它由程序员自己定义,可以包含多个其他类型的数据。

定义结构体的一般格式为:

struct

{

char *name;  //姓名

intnum;  //学号

int age;  //年龄

char group;  //所在小组

float score;  //成绩

} stu1;

  1. 结构体是一种集合,它里面包含了多个变量或数组,结构成员可以为整型、浮点型、字符型、指针型和无值型。
  2. 除了可以对成员进行逐一赋值,也可以在定义时整体赋值。
  3. struct结构体,在结构体定义的时候是不会分配内存空间,不过如果是声明结构体变量的时候就会分配空间。
  4. 结构体不可以给结构体内部变量初始化

例如:初始化学生的成绩都为0:

struct student

{

int name;

int score=0;         非法

}A;

struct student

{

int name;

int score;

} A;

A.score=0;           正确

  1. 结构体名是结构体的标识符不是变量名。
  2. 结构体是一个新的数据类型, 因此结构体变量也可以象其它类型的变量一样赋值,运算。不同的是结构变量以成员作为基本变量。

例如:给学生的成绩赋值

struct student

{

int name;

int score;           非法

}A;

Score=100;

struct student

{

int name;

int score;

} A;

A.score=100;          正确

  1. 可以传递一个结构体作为函数的参数,非常类似传递任何其他变量或指针。
  2. 用关键字typedef定义结构体,在C语言中,typedef的作用是为数据类型(包括C语言的内置类型)定义一个新的名字,就是取别名的意思,用typedef定义结构体的形式如下:

typedef struct 结构名{

数据成员1;

数据成员2;

......

数据成员n;

}结构体别名;

第九章 实战练习

  1. 输入并保存10个学生的姓名和出生日期,用student类型实现1个选手的数据定义、输入和输出。
  2. 参加比赛的每个选手都具有姓名、编号、出场次序等信息,要求用结构体实现如下功能:
    • 正确定义选手信息所对应的数据类型,person。
    • 用person类型实现1个选手的数据定义、输入和输出。
    • 输入并保存5个选手的信息,并能随机查询第i个选手的具体信息。
  3. 某单位进行选举,有5位候选人:jia,yi,bing,ding,wu。编写程序,统计每人所得的票数。要求每人的信息里包括两部分:name和votes,分别描述姓名和所得票数。每个人的信息用一个结构体来表示,5个人的信息使用结构体数组。找出票数最多的选手并输出其票数。
  4. n只猴子围坐成一个圈,按顺时针方向从1到n编号。然后从1号猴子开始沿顺时针方向从1开始报数,报到m的猴子出局,再从刚出局猴子的下一个位置重新开始报数,如此重复,直至剩下一个猴子,它就是大王。输出猴王的编号。
  5. 平面上有n个点,坐标均为整数。横坐标相同时按纵坐标排序,否则按横坐标排序。本题要求用结构体存储坐标,再进行排序。先升序排序输出,再降序排序输出,可以自己写排序函数,也可以用qsort库函数排序。输出有两行,即排序后的点,格式为(u,v),每个点后有一个空格。第一行升序排序结果,第二行降序排序结果。

第十一章 实战经验

  1. 定义指向文件类型的指针变量的时候,变量的类型为FILE,不能用小写只能是大写。例如:file * fp;是非法的。

正确的应该是:FILE * fp;。

  1. .文件的打开
  • 打开文件时,传入路径的格式容易出错。fopen("filePath","r");注意转义字符造成的错误。

例如:打开"D:\user\a.txt"这个文件,这样\u和\a是被转义的字符,不能被编译器正确编译。

正确的应该是:"D:\\user\\a.txt"或者"D:/user/a.txt" 。

例如:fopen("D:\user\a.txt","r");是错误的。

正确的应为:fopen("D:\\user\\a.txt","r");或者fopen("D:/user/a.txt","r");。

  • 以只读方式打开不存在的文件,则会打开文件失败。fopen("filePath","r");所打开的文件必须是已经存在的,否则就会出现错误,常用下面的方法打开文件

if((fp=fopen("file1","r"))==NULL)

{

printf("cannot open this file\n");

exit(0);

}

  • 一些常见的文件打开方式及错误

r 打开只读文件,该文件必须存在。

r+ 打开可读写的文件,该文件必须存在。

w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。

w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。

a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。

a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。

  1. 文件的读写

fgets(str,n,fp)遇到换行或者文件末尾会提前结束。例如文件中有以下字符

hello word

my name is liHua.

使用fgets(str,15,fp)读文件时,实际上只会读入第一行的内容,虽然要求读入15个字符,但提前遇到了换行,所以就此终止了。

  1. 如果文件打开后忘记关闭,虽然系统会自动关闭所有文件,但可能会数据丢失。因此在文件使用完后必须关闭文件。

第十一章 实战练习

  1. 字符输入:

从键盘输入一些字符,逐个把它们送到磁盘上去,直到输入”#”结束。

  1. .文件复制:

一个文件的信息复制到另一个文件.今要求将上例建立的file1.dat文件中的内容复制到另一个磁盘文件file2.dat中。

  1. 文件排序保存

从键盘中输入若干个字符,对它们按字母大小排序,然后将排好序的字符串送到磁盘文件中保存。

  1. 文件保存

从键盘输入10个学生的有关数据,然后把它们转存到磁盘文件上。

评论

0条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注