编程练习(续)
2.
请编写一个函数,删除一个字符串的一部分。函数的原型如下:
int del_substr(char *str,char const *substr)
函数首先应该判断substr是否出现在str中。如果它并未出现,函数就返回0;如果出现,函数应该把str中位于该子串后面的所有字符复制到该子串的位置,从而删除这个字串,然后函数返回1。如果substr多次出现在str中,函数只删除第1次出现的字串。函数的第2个参数绝对不会被修改。
举个例子,假定str指向ABCDEFG。如果substr指向FGH、CDF或XABC,函数应该返回0,str未作任何修改。但如果substr指向CDE,函数就把str修改为指向ABFG,方法是把F、G和结尾的NUL字节复制到C的位置,然后函数返回1。不论出现什么情况,函数的第2个参数都不应该被修改。
和上题的程序一样(上一题在我上一篇blog末尾):
a.你不应该使用任何用于操纵字符串的库函数(如strcpy,strcmp,等)。
b.函数中的任何地方都不应该使用下标引用。
一个值得注意的是,空字符串是每个字符串的一个子串,在字符串中删除一个空子串字符串不会产生变化。
程序如下:
#include<stdio.h>
int del_substr(char *str,char const *substr);
void main()
{
char s[15]="ABCDEFG",t[3]="CDE";
printf("str=%s\nsubstr=%s\n",s,t);
del_substr(s,t);
printf("The deleted string is: ");
puts(s);
}
int del_substr(char *str,char const *substr)
{
int flag=0,n;
char *st=str; //将str的值赋给指向字符型指针的st
char *su=(char*)substr;
char *st_r,*su_b;
while(*st){ //当指针变量st所指向的对象存在,whlie(*st)等价于while(*st!=0)
if(*st==*su){ //st与su指向同一个地址单元,即字符C
st_r=st; //st_r为CDEFG
su_b=su; //su_b为CDE
n=0;
while(*st_r&&*su_b){ //当指针变量st_r与su_b所指向的对象存在
if(*st_r!=*su_b) break; //当st_r与su_b指向的字符不等时,即st_r为FG时,则跳出while循环
else{ //当st_r与su_b都指向C时,各自加1
st_r++;su_b++;n++; //n代表了st_r与su_b相等的字符数,即n=3
}
} //这里的while语句主要为计算n
if(!(*su_b)){ //如果此时以su_b变量内容为地址的那个变量不存在
st_r=st+n; //令st_r赋值为st中位于相同字符串后面的所有字符,即FG
while(*st_r){ //当st_r所指向的对象为真,即FG存在
*(st_r-n)=*st_r; //将FG赋值到(与su_b)相同字符串的位置,即将指向C变为指向F
st_r++; //在这个例子中加到G即可
}
}
*(st_r-n)='\0'; //此时执行完毕的字符串应以NUL结尾
}
st++; //若st与su指向的地址单元不同,则继续比较下一个地址单元
}
return 0;
}
运行结果:
flag不是c语言的关键字,其通常用来作为一个指示变化的变量的名称,C语言中一般设置一个变量flag,是一个来表示判断的变量,当做标志。
例如当一种情况的时候,置flag为1,当另外一种情况时,置flag为2。 变量名为flag,只是习惯问题,也可以取别的名字。
一个变量的指针的含义包含两个方面:
1.是以存储单元编号表示的地址(如编号为2000的字节);
2.是它指向的存储单元的数据类型(如int,char,float 等)。
指针变量中只能存放地址(指针),不可将一个整数赋给一个指针变量。
*p ——取出以p变量内容为地址的那个变量的值
若要通过函数改变某个变量的值,必须传入这个变量的地址然后用指针进行修改。
引用数组中各元素的值有3种方法:
(1)下标法,如a[i]形式;
(2)指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量。
3.
编写函数reverse_string,它的原型如下:
void reverse_string(char *string);
函数把参数字符串中的字符反向排列。请使用指针而不是数组下标,不要使用任何C函数库中用于操纵字符串的函数。
提示: 不需要声明一个局部数组来临时存储参数字符串。
分析: 这个算法的关键是当两个指针相遇或擦肩而过时就停止。否则,这些字符将翻转两次,实际相当于没有任何效果。
程序如下:
//函数把参数字符串中的字符反向排列
#include<stdio.h>
void reverse_string(char *string);
int main(){
char string[]="ABCDEFG";
printf("The original string :%s\n",string);
reverse_string(string);
printf("The anti_string :%s",string);
return 0;
}
/*翻转参数字符串*/
void reverse_string(char *string){
char *last_char=string;
//将last_char设置为指向字符串的最后一个字符
while(*last_char!='\0')
last_char++; //while循环结束后,last_char指向NUL
last_char--; //向前退一个单元,last_char指向字符串最后一个字符G
/*交换string和last_char指向的字符,string前进一步,
last_char后退一步,在两个函数擦肩而过之前重复此过程 */
while(string<last_char){
char temp=*string;
*string=*last_char;
*last_char=temp; //string和last_char所指向的字符互换
string++; //string前进一步,即接下来指向B
last_char--; //last_string后退一步,即指向F
}
}
运行结果:
关于字符串的翻转,还可以使用递归的方法:
#include<stdio.h>
int main(int argc)
{
char c=getchar();
if(c!='\n')
{
main(0);
putchar(c);
}
if(argc) putchar('\n');
return 0;
}
这一章节的有些程序会稍微牵扯到链表等数据结构
若提前有一定算法基础的,便不会花费太多时间了
关于《C程序设计》这本书,细节方面真的是很棒了
之前甚觉繁琐,而现今编程遇到问题时
才觉得繁(xiang)琐(xi)有多可贵
很多知识点只有在上手编程的过程中 才能深刻理解与掌握
指针先生,久仰大名,您可真是百闻不如一用呢