1
四,strcat函数合并字符串五,strcmp函数比较字符串六、字符串排序算例七,memcpy函数拷贝内存八、程序的入口函数 main
2
四,strcat函数合并字符串函数原型,char* strcat (char *dst,const char*src);
作用:将 src字符串追加到 dst定位的内存空间中,dst必须有终止符等待 src的第一个字符串覆盖,源串也应有终止符结束追加的收尾工作,函数返回目标串的原入口地址。
功能模拟:
#include<string.h>
#include<stdio.h>
char* strcat1 (char *dst,const char*src)
{ unsigned int i=0;
while (dst[ i ]!='\0') i++;
while ((dst[ i ]=*src)!='\0'){i++;src++;} return dst;
}
3
void main (void)
{ char c[32]="abcd"; char *p="-efg";
strcat1 (c,p); p="-hijk" ;
printf ("%s\n",strcat (c,p));
}
//输出,abcd-efg-hijk
注意:
如果将上面 while(dst[i]!='\0') i++;改为 while(dst[i++]!='\0');
其余不变则 vc6.0输出结果 abcd-hijk ;这是因 while(dst[i++])
的幕后分解是不确定的。
4
五,strcmp函数比较字符串函数原型,int strcmp (const char*s1,const char*s2);
作 用:比较串 1和串 2,s1==s2,结果为 0,s1>s2,结果为 1,
s1<s2,结果为 -1。
功能模拟:
int strcmp1(const char*s1,const char*s2)
{ while (*s1==*s2)
{ if (*s1=='\0') return 0; s1++; s2++; }
if (*s1>*s2) return 1; return -1;
}
#include<string.h>
#include<stdio.h>
5
void main (void)
{ char sa[ ] = "abCd";
const char *sb = "abcd";
char *sc = "abcd";
if ( strcmp (sc,sb) == 0)
printf ("sc=sb-- %s\n",sc);
printf ("strcmp (sa,sb) = %d\n",strcmp1 (sa,sb));
printf ("strcmp(sb,sa) = %d\n",strcmp (sb,sa));
}
注意:
if (“aa”==“aa”)是关于两个字符串首地址的相同关系比较,比较的结果是不确定的。
6
六、字符串排序算例
[例 ] 排序法对多个字符串按字母次序排列
# include<stdio.h>
#include<string.h>
inline void swap (char*& x,char*& y)
{char* p=x; x=y; y=p;}
void SelectSort (char* a[],int n)
{ for (int i=0; i<n-1; i++)
{ int min=i;
for (int j=i+1; j<n; j++)
if (strcmp (a[ j ],a [ min ])<0) min=j;
if (min!=i) swap (a[ i ],a[ min ]); }
}
7
void ExchangeSort (char* a[ ],int n)
{ for (int i=0;i<n-1;i++)
for (int j=i+1; j<n; j++) if (strcmp (a[i],a[j])>0)
{ char *p=a[ i ]; a[ i ]=a[ j ]; a[ j ]=p; } }
void main (void)
{char *ca[ ]={"For","Before","FOR","And","anyone"};
const int n=sizeof (ca)/sizeof (ca[0]); int k;
for( k=0;k<n;k++)
printf ("%p->%s ",ca[k],ca[k] );
typedef void (*VCI)(char*[ ],int);
VCI pfn[3]= { SelectSort,ExchangeSort };
k=1; //k取值 0,1输出效果相同
(*pfn[k]) (ca,n); printf ("\n after Sort\n");
for( k=0;k<n;k++) printf ("%p->%s ",ca[k],ca[k]);
}
8
输出结果,
0042001C->For 00420F74->Before 00420F8C
->FOR 00420F84->And 00420F90->anyone
after Sort
00420F84->And 00420F74->Before 00420F8C
->FOR 0042001C->For 00420F90->anyone
从上可见字符串常数的首地址与偶地址齐平,各只读字符串相互之间未必首尾相连。
但长度不一的字符串共同的特定是以 '\0'作为结尾符,这保证 strcmp函数的正常比较操作。
9
Fo r '\0'0042001C
B e f o r e '\0'00420F74C
a n y o n e '\0'00420F90
FO R '\0'00420F8C
An d '\0'00420F84C
ca[0]
ca[1]
ca[2]
ca[4]
ca[3]
排序前后指针数组元素的值
10
七,memcpy函数拷贝内存
memcpy函数原型为:
void* memcpy (void *dst,const void*src,size_t n) ;
函数 memcpy将源地址 src起始的其后的 n个字节拷贝到
dst定位的内存空间中。
memcpy完成集合数据的拷贝效率高且界面简单。源内存段的数据可以方便地拷贝到目标内存段。
该函数的功能异常强大,因此应确保拷贝时两内存段是有定义的,防止越界。上面拷贝数组 e[3]到数组 d[5],两者维数不一致,目标数组维数大,这种拷贝是安全的。
如果 src和 dst被 n界定的两个内存段中若存在重迭的交集,拷贝的结果是危险的,应予以避免。
11
memmove具有与 memcpy相同的功能,将 src[0]
~src[n-1]的内容拷贝到 dst[0]~dst[n-1]中,但 memmove函数提供一道安全措施确保 src和 dst引领的内存段交错时亦能复制正确的结果,但程序效率因其缓冲作用而打一个折扣。
运转机制如下:
void* memmove1(void *dst,const void*src,size_t n)
{ unsigned char* ph= new unsigned char[n];
//定义 heap空间的缓冲数组 ph[n];
memcpy (ph,src,n); //拷贝源数据 src到缓冲区
memcpy (dst,ph,n); //将缓冲区的数据再送至目标区
delete [ ] ph; //删除缓冲区
return dst; //返回原目标地址
}
12
[例 ] 内存拷贝运算
#include<string.h>
#include<stdio.h>
void* memcpy1(void *dst,const void*src,size_t n)
{ char* pd=( char*)dst; char* ps=( char*)src;
unsigned int k=0;
while (k< n )
{ *pd++=*ps++; k++;} return dst;}
void main (void)
{ long e[ ]={1,2,3}; long d[5];
memcpy1(d,e,sizeof(e));
memcpy(d+3,e+1,sizeof(long[2]));
printf("d=[%d,%d,%d,%d,%d]\n",d[0],d[1],d[2],d[3],d[4]);
}
13
八、程序的入口函数 main
C/C++语言是函数驱动的,在 dos下函数的入口为
main函数,在 WINDOWS编程模式下函数的入口 WinMain
函数,程序的入口函数是计算机将控制从操作系统或其它程序转换到用户代码的启动点。
程序从包含唯一的 main函数的程序单元开始执行,如果 main之前存在全局对象则先执行相应的构造函数再进入
main函数。
main函数是标准控制台或 dos应用程序的入口点。
14
main函数的定义格式有两种,一种是无参格式,无参格式圆括号中的 void可以省略不写,
void main(void) int main()
{ { 语句序列;
语句序列; return 1;
} }
另一种是带参数的格式:
int or void main (int argc,char*argv[ ])
{ 语句序列; }
带参数的格式标题头中的字符指针数组 char * argv[ ]
可等价地改为 char ** argv 。其形参标识符的命名和作用域遵循普遍函数形参的规定,但习惯于用 argc标明第一个形参名,argv标明第二个形参名。用其它的名称也是可以的。
15
main函数的返回类型可以是 int 型或 void型,int 型函数的返回常与 return en语句匹配,en是整型表达式。
如果 main函数中不使用 return语句返回值,在函数的标题头的函数名前加上关键字 void。
main函数的的控制转移可用 exit函数来实现,因此
void 型 main函数不阻止程序通过其它函数返回一个出口状态值。
带命令行参数的 main函数可以视为操作系统调用的函数,命令行参数就是操作系统传递给 main函数的入口形参,入口形参的类型抽象为 void main(int,char* [ ]),第一个形参规定为 int类型,第二个形参规定为字符型的指针数组。
这两者是键入命令参数时动态确定的。
16
在 dos下键入命令的形式为空格分隔的文本串序列:
命令名 文本串 1 文本串 2,.,文本串 n?
main函数的形参指针数组各元素与文本串实参对应匹配关系为:
argv[0],argv[1],argv[2],..,
argv[n=argc-1],argv[argc=n+1]=0
系统为动态键入的文本串分配一定的内存。
argv[0]指向调用程序的命令名,argv[1]指向第一个命令行参量即文本串 1的首地址,...,argv[argc-1]= argv[n]指向文本串 n的首地址,直到 argv[argc],它总是 NULL即 0。
17
argc是系统根据用户实际输入命令名后的文本串数加上命令名代表的一个文本串得到的正数 (argc=n+1)。 argc总是大于或等于 1。例如,
copy c:\arj.exe d:\arj.exe?
作为文本串的命令名为 copy,文本串 1为 c:\arj.exe,
文本串 2 为 d:\arj.exe。
argc系统确定为 3,argv[3]=0。
argv[0]存放 copy的首地址,argv[1]指向 c:\arj.exe的首地址,argv[2]存放 d:\arj,exe的首地址。
18
[例 ] a.cpp 简单的 void型无入口形参的 main函数
# include <stdio.h>
void show (int argc,char* argv[ ])
//指针数组形参 char* argv[ ]等价于 char** argv
{ argc =0;
while (*argv)
printf ("argv [%d]=%s\n",argc++,*argv++);
printf ("argv [%d]=%d\n",argc,(char)*argv);
}
void main (void)
{ char* argv [ ]= {"c:\\a.exe","a","bb",0};
int argc = sizeof (argv)/sizeof (argv [0]);
printf ("argc=%d\n",argc);
show (argc,argv);
}
19
[例 ] m.cpp带命令行参数的 main函数
# include <stdio.h>
extern void show (int argc,char* argv[ ]);
void main (int argc,char* argv[ ])
{ printf ("argc=%d\n",argc);
show ( argc,argv);
}
20
不加引号的结果如下,加引号的结果如下,
E:\>m a bb? E:\>m "a bb "?
argc=3 argc=2
argv[0]=E:\M.EXE argv[0]=E:\M.EXE
argv[1]=a argv[1]=a bb
argv[2]=bb argv[2]=0
argv[3]=0
21
[例 ] echo.cpp的执行文件 echo.exe在根目录 C:\下
# include<stdio.h>
void main(int argc,char** argv)
{ for (register int k=1; k<argc; k++)
printf ("%s%c",argv[k],(k<argc-1)?' ':'\n');
}
//程序运行如下 (不输出执行文件的命令名 ):
C:\>键入 echo xxxx dddd? 得到输出,xxxx dddd
22
[例 ] a.cpp的执行文件 a.exe在根目录 C:\下,输出执行文件的命令名
# include <stdio.h>
void main (int n,char* s[ ])
{ for (;n>0;n--,s++)
printf ("%s,",*s);
}
C:\>键入 a xxxx dddd?
得到输出,C:\a.exe,xxxx,dddd,
23