}
2、编程实现:
输入一个字符串,内有数字和非数字符号,如:
a123x45617960?
302tab5876。
将其中连续的数字作为一个整数,依次存放到一个数组a中。
例如:
123放在a[0]中,456放在a[1]中……试统计共有多少个整数,并输出这些数。
要求添加合适的注释。
3、利用指向指针的指针方法对6个字符串按字典顺序排序并输出。
4、利用指向指针的指针的方法对N个整数排序并输出。
5、编程实现,先读入一段正文,然后删除其中单词from、in、at、an和on,最后显示该结果文本段。
6、理解教材示例:
例6.9,例6.10,例6.14
三、补充资料
关于内存的管理在C/C++中的深度理解:
内存分配方式有三种:
(1)从静态存储区域分配。
内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。
例如全局变量,static变量。
(2)在栈上创建。
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
栈内存分配运算内置于处理器的指令集中,效率很高,管理自动,但是分配的内存容量有限。
(3)从堆上分配,亦称动态内存分配。
程序在运行的时候用malloc或new(C++运算符)申请任意多少的内存,程序员自己负责在何时用free或delete(C++运算符)释放内存。
动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
malloc/free的使用要点
函数malloc的原型如下:
void*malloc(size_tsize);
用malloc申请一块长度为length的整数类型的内存,程序如下:
int*p=(int*)malloc(sizeof(int)*length);
我们应当把注意力集中在两个要素上:
“类型转换”和“sizeof”。
◆malloc返回值的类型是void*,所以在调用malloc时要显式地进行类型转换,将void*转换成所需要的指针类型。
◆malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
我们通常记不住int,float等数据类型的变量的确切字节数。
例如int变量在16位系统下是2个字节,在32位下是4个字节;而float变量在16位系统下是4个字节,在32位下也是4个字节。
在malloc的“()”中使用sizeof运算符是良好的风格,但要当心有时我们会昏了头,写出p=malloc(sizeof(p))这样的程序来。
◆函数free的原型如下:
voidfree(void*memblock);
为什么free函数不象malloc函数那样复杂呢?
这是因为指针p的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。
如果p是NULL指针,那么free对p无论操作多少次都不会出问题。
如果p不是NULL指针,那么free对p连续操作两次就会导致程序运行错误。
常见的内存错误及其对策如下:
◆内存分配未成功,却使用了它。
编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。
常用解决办法是,
在使用内存之前检查指针是否为NULL。
如果是用malloc或new来申请内存,应该用if(p==NULL)或if(p!
=NULL)进行防错处理。
例如:
char*p=(char*)malloc(100);
if(p==NULL)exit
(1);
strcpy(p,“hello”);
◆忘记了释放内存,造成内存泄露。
含有这种错误的函数每被调用一次就丢失一块内存。
刚开始时系统的内存充足,你看不到错误。
但最终程序会突然死掉,系统出现提示:
内存耗尽(outofmemory)。
动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(C++中采用的new/delete同理)
例如:
voidGetMemory(char*p,intnum)
{
p=(char*)malloc(sizeof(char)*num);
}//不要以为局部变量p的内存空间会自动被回收,就能保证指针p指向的内存空间也会被回收,这是做不到的。
voidmain()
{
char*str=NULL;
GetMemory(str,100);//str仍然为NULL,形参的变化不影响实参
strcpy(str,"hello");//运行错误,同时另外隐藏的问题就是malloc分配的堆空间没有被释放
}
◆释放了内存却继续使用它。
有三种情况:
(1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。
(2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”,因为该内存在函数体结束时被自动销毁。
(3)使用free或delete释放了内存后,没有将指针设置为NULL。
导致产生“野指针”
例如:
char*p=(char*)malloc(100);
if(!
p)exit
(1);
strcpy(p,“hello”);
free(p);//p所指的内存被释放,但是p变量本身空间没有释放,其值代//表的所指内存的地址仍然不变。
…
if(p!
=NULL)//没有起到防错作用
{
strcpy(p,“world”);//出错,即便p不是NULL指针,它已不指向合法//的内存块
}//此时的p指针是典型的“野指针”,它所指内存中保存的是垃圾内容。
从上面的分析可以发现指针有一些“似是而非”的特征:
(1)指针变量本身消亡了,并不表示它所指的内存会被自动释放。
(2)内存被释放了,并不表示指针会消亡或者成了NULL指针。
要坚决杜绝“野指针”,“野指针”不是NULL指针,是指向“垃圾”内存的指针。
人们一般不会错用NULL指针,因为用if语句很容易判断。
但是“野指针”是很危险的,if语句对它不起作用。
“野指针”产生的原因:
(1)指针变量没有被初始化。
任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。
所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
例如
char*p=NULL;
char*str=(char*)malloc(100);
(2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
如上例。
试着单步跟踪分析下面程序出现乱码而不输出helloworld的原因:
#include
char*GetString(void)
{
charp[]="helloworld";
returnp;//p指针指向哪一类内存空间?
}
voidmain(void)
{
char*str=NULL;
str=GetString();
cout<}写出你对结果的理解。
实验五、指针、函数程序设计
一、实验目的:
1.理解函数定义和函数原型说明的方法,掌握函数调用中实参与形参的对应关系,理解“传值”和“传指针”;
2.掌握递归函数定义和调用的方法。
3.掌握指针和函数的结合
4.掌握含多个源文件的程序的编译、连接和调试运行的方法。
5.进一步熟悉C开发环境中调试的使用
二、实验内容:
在实际的程序设计中,通常要求实现在A函数中使用B函数中定义的数组,这就要需要传递数组的指针,实参常用数组名或指针变量来表示,B函数的形参用形参数组名变量或指针变量来表示,它们的参数传递通常有四种组合。
【1】intmax(intx[],intn)
{
inti,max;
max=x[0];
for(i=1;iif(x[i]>max)max=x[i];
returnmax;
}
voidmain()
{
inta[10],i;
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
max(a,10);
...
}
【2】intmax(int*x,intn)
{
int*p,max;
max=*x;
for(p=x+1;pif(*p>max)max=*p;
returnmax;
}
voidmain()
{
inta[10],i,*p;
for(i=0;i<10;i++)
scanf(“%d”,&a[i]);
p=a;
max(p,10);
...
}
【3】intmax(intx[],intn)
{