C语言家教记录(八)
导语
本次授课的内容如下:指针的高级应用,流和文件
辅助教材为 《C语言程序设计现代方法(第2版)》
指针的高级应用
动态分配、使用、释放
malloc,calloc(一般不用),realloc(一般不用)
null 空指针,也可以用0
null的使用
c
if(p==NULL)
if(!p)
if(p!=NULL)
if(p)
malloc的使用
c
p=malloc(n+1);//不常用
p=(char*)malloc(n+1);//常用,malloc的分配单位是字节
int* a;
a=malloc(n*sizeof(int));
for(int i=0;i<n;i++)a[i]=0;
calloc的使用
c
a=calloc(n,sizeof(int));//自动初始化
struct point { int x, y; } *p;
p = calloc(1, sizeof(struct point));//x,y都为0
realloc的使用,规则见书
c
realloc(p,n*sizeof(int));
释放存储空间,例子见书
c
p=malloc();
q=malloc();
free(p);
p=q;
char*p=malloc(...);
free(p);
strcpy(p,"abc");//报错,悬空指针问题
示例程序
c
char *concat(const char *s1, const char *s2)
{
char *result ;
result = malloc(strlen(s1) + strlen(s2) + 1);
if (result == NULL) {
printf("Error: malloc failed in concat\n");
exit (EXIT_FAILURE);
}
strcpy(result, s1);
strcat(result, s2);
return result;
}
p=concat("abs","def");
链表
概念和例子见书
c
struct node
{
int value;
struct node *next;
};//链表的节点定义
struct node* first =NULL;
//节点的创建,图见书
struct node* p;
p=malloc(sizeof(struct node));
(*p).value=10;
//等价于
p->value=10;
示例程序
解释插入链表的实现,解释图
c
struct node *add_to_list(struct node *list, int n)
{
struct node *new_node;
new_node = malloc(sizeof(struct node));
if (new_node == NULL) {
printf("Error: malloc failed in add_to list\n");
exit(EXIT_FAILURE);
}
new_node->value = n;
new_node->next = list;
return new_node;
}
搜索链表,用书上例子解释
c
struct node *search_list(struct node *list, int n)
{
struct node *p;
for (p = list; p != NULL; p = p->next)
if (p->value == n)
return p;
return NULL;
}
struct node *search_list(struct node *list, int n)
{
while (list != NULL && list->value != n)
list = list->next;
return list;
}
删除节点,根据书上例子
c
struct node *delete_from_list(struct node *list, int n)
{
struct node *cur, *prev;
for (cur = list, prev = NULL;
cur != NULL && cur->value != n;
prev = cur, cur = cur->next)
;
if (cur == NULL)
return list; /* n was not found */
if (prev == NULL)
list = list->next; /* n is in the first node */
else
prev->next = cur->next; /* n is in some other node */
free (cur);
return list;
}
指向指针的指针
如果不进行返回,添加结点可能会失效,见书上例子
c
void_add_to_list(struct node **list, int n)
{
struct node *new_node;
new_node = malloc(sizeof(struct node));
if (new_node == NULL) {
printf("Error: malloc failed in add_to_list\n");
exit(EXIT_FAILURE);
}
new_node->value = n;
new_node->next = *list;
*list = new_node;
}
指向函数的指针
c
void (*pf)(int);
pf=f;//赋值
(*pf)(i);//调用
pf(i);//调用
//pf 可以指向任何带有int 型形式参数并且返回void 型值的函数
double integrate(double (*f)(double), double a, double b);
double integrate(double f(double), double a, double b);//等价
result=integrate(sin,0.0,PI/2);
integrate内可以调用
y=(*f)(x);
qsort函数
c
void qsort(void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *));//函数原型
qsort(inventory, num_parts, sizeof(struct part), compare_parts);//调用格式
int compare_parts(const void *p, const void *q)
{
const struct part *p1 = p;
const struct part *q1 = q;
if (p1->number < q1->number)
return -1;
else if (p1->number == q1->number)
return 0;
else
return 1;
}
//等价于
int compare_parts(const void *p, const void *q)
{
return strcmp(((struct part *) p)->name,
((struct part *) q)->name);
}
流和文件
流
stdin,stdout,stderr简单介绍
简单介绍二进制文件
简单介绍输入输出重定向和命令行
文件操作
fopen,fclose,freopen等
tmpfile,fflush,remove,rename跳过
c
FILE *fopen(const char * restrict filename, const char * restrict
mode);//函数原型
fp=fopen("a.txt","r");//路径和模式,运行之后输入从键盘改成文件
//解释参数r w a r+ w+ a+,参数可以组合
int fclose(FILE *stream);//关闭文件
FILE *freopen(const char * restrict filename, const char * restrict mode, FILE * restrict stream);//重定向
if (freopen("foo","w", stdout) == NULL) {
/* error; foo can't be opened */
}//最好先关闭再重定向
//解释从命令行获取文件名
int main(int argc, char *argv[])
{
...
}
示例程序
c
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "example.dat"
int main(void)
{
FILE *fp;
fp = fopen(FILE_NAME, "r");
if (fp == NULL) {
printf("Can't open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
...
fclose(fp);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *fp;
if (argc != 2) {
printf("usage: canopen filename\n");
exit (EXIT_FAILURE);
}
if ((fp = fopen(argv[1], "r")) == NULL) {
printf("%s can't be opened\n", argv[1]);
exit (EXIT_FAILURE);
}
printf("%s can be opened\n", argv[1]);
fclose(fp);
return 0;
}
变量和格式化io
简介fprintf和printf,见书
简介fscanf和scanf,见书
简介fputc,putc,putchar,fgets,gets
sprintf,snprintf,针对字符数组的输出
sscanf,针对字符数组的输入
文件定位和块输入输出跳过,简单勾一下
示例程序
c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
FILE *source_fp, *dest_fp;
int ch;
if (argc != 3) {
fprintf(stderr, "usage: fcopy source dest\n");
exit(EXIT_FAILURE);
}
if ((source_fp = fopen(argv[1], "rb")) == NULL) {
fprintf (stderr, "Can't open %s\n", argv[1]);
exit(EXIT_FAILURE);
}
if ((dest_fp = fopen(argv[2], "wb")) == NULL) {
fprintf (stderr, "Can't open %s\n", argv[2]);
fclose(source_fp);
exit(EXIT_FAILURE);
}
while ((ch = getc(source_fp)) != EOF)
putc (ch, dest_fp);
fclose(source_fp);
fclose(dest_fp);
return 0;
}
总结和复习
本次授课讲述第17章和第22章内容,关键点:指针的高级应用和输入输出