c中几个copy函数的使用细节

编程语言及工具

104人已加入

描述

  在linux c编程中,拷贝函数可以说是无处不用,结合我最近的一些实践,简单研究一下这几个函数。说说实际使用中容易出错的地方。

  strcpy: 最常用的字符串拷贝函数,但是要注意这个函数不会自己判断源字符串是否比目标空间大,必须要程序员自己检查,否则很容易造成拷贝越界,下面是几个例子:

  char *a = “0123456789”, *b = “abcdefghijk”;

  char c[5];

  输出: strcpy(c,a)=0123456789 //数组c只有5个字节的空间,但是经过strcpy后a的剩余字符也拷贝过去了,如果c后面是系统程序空间,那就要出问题了。

  strncpy:strcpy的改进版本,多了一个拷贝长度的参数。需要注意的是长度参数应该为目的空间的大小,并且这个函数不会自己附加字符串结束符‘\0’,要自己加。看下面的例子:

  strncpy(c,b,strlen(b))=abcdefghijkw //拷贝长度不对,还是越界

  strncpy(c,a,sizeof(c))=01234fghijkw //拷贝长度正确,但是因为拷贝长度内不包括‘\0’,所以输出的时候还是会把原本的空间内容输出,知道遇到一个结束符‘\0’。

  所以正确的做法应该是: strncpy(c, a, sizeof(c)-1); c[5] = ‘\0’;

  memcpy: 最后说一下这个函数,这个函数是个很强大的工具,因为它可以简单的根据字节数拷贝内存空间内容,所以经常被用于结构体的拷贝。需要注意两点:1、memcpy拷贝的时候源空间的长度和目标空间的长度都需要程序员自己考虑,如果按照源空间的长度拷贝,要注意是否会写溢出,如果按照目标空间的长度拷贝,则要考虑是否造成读溢出(把不该拷贝的内容也拷贝过去了),而读溢出在某些系统环境下(比如AIX),可能会造成coredump(当读到不该读的地址);2、源空间和目标空间不能重叠。如下例:

  char src1[] = “src1”, src2[]=“source2, this is a long src”;

  char dest[] = “destination”;

  输出:

  memcpy(dest, src1, strlen(dest)) = src1 //读越界

  memcpy(dest, src2, strlen(src2)) = source2, this is a long srcis is a long src //写越界

  memcpy(dest, dest+2, strlen(dest2) = stination // 重叠,结果是混乱

  copy函数的使用细节

  strcpy是拷贝字符串,以\0为标志结束(即一旦遇到数据值为0的内存地址拷贝过程即停止)

  strcpy的原型为

  char *strcpy(char *dest, const char *src)

  而memcpy是给定来源和目标后,拷贝指定大小n的内存数据,而不管拷贝的内容是什么(不仅限于字符)

  memcpy的原型为

  void *memcpy(void *dest, const void *src, size_t n);

  C语言中的exit()函数,括号中有时为1,有时为0在main函数中我们通常使用return (0);这样的方式返回一个值。

  但这是限定在非void情况下的也就是void main()这样的形式。

  exit()通常是用在子程序中用来终结程序用的,使用后程序自动结束跳会操作系统。

  但在如果把exit用在main内的时候无论main是否定义成void返回的值都是有效的,并且exit不需要考虑。括号中有时为1,有时为0

  遇到1 就代表出错后结束程序~其实不一定是1的~非0值也可以!遇到0就表示正常退出~~

  例如:

  你定义一个文件的指针fp

  if (fp=fopen (“c:\\abc.txt”,“r”))==NULL)

  {

  printf(“Can not open the file.\n”);

  exit(1);

  }

  如果文件不存在那么就跳出程序了 如果用struct的话,注意以下几点:

  1.尽量使用占为少的类型,如,在可能的时候使用short代替int

  2.按数据类型本身占用的位置从大到小排列

  例如

  struct{

  int a;

  char b;

  int c;

  char d;

  }

  应该写为:

  struct{

  int a;

  int c;

  char b;

  char d;

  };

  一般的编译器会采取一种叫做填充(padding)的方式来对齐数据。

  以一个机器字(比如在32-bit的机器上为word = 32bit.)为基础进行填充。

  像上面的struct会这样存储:

  (xp,vc6.0)

  a 32bit = 4byte

  c 32bit = 4byte

  b,d,*,* 32bit = 4byte

  其中,两个*号表示填充(但是并没有使用那两个位置。)

  system函数:参数放入的是一个命令。

  #include 《sys/types.h》

  #include 《sys/wait.h》

  #include 《errno.h》

  #include 《unistd.h》

  int system(const char * cmdstring)

  { pid_t pid;

  int status;

  if(cmdstring == NULL){

  return (1);

  }

  if((pid = fork())《0){

  status = -1;

  }

  else if(pid = 0){

  execl(“/bin/sh”, “sh”, “-c”, cmdstring, (char *)0);

  -exit(127); //子进程正常执行则不会执行此语句

  }

  else{

  while(waitpid(pid, &status, 0) 《 0){

  if(errno != EINTER){

  status = -1;

  break;

  }

  }

  }

  return status;

  }

  先分析一下原理,然后再看上面的代码大家估计就能看懂了:

  当system接受的命令为NULL时直接返回,否则fork出一个子进程,因为fork在两个进程:父进程和子进程中都返回,这里要检查返回的pid,fork在子进程中返回0,在父进程中返回子进程的pid,父进程使用waitpid等待子进程结束,子进程则是调用execl来启动一个程序代替自己,execl(“/bin/sh”, “sh”, “-c”, cmdstring, (char*)0)是调用shell,这个shell的路径是/bin/sh,后面的字符串都是参数,然后子进程就变成了一个shell进程,这个shell的参数

  是cmdstring,就是system接受的参数。在windows中的shell是command,想必大家很熟悉shell接受命令之后做的事了。

  rewind函数用于把fp所指文件的内部位置指针移到文件头

  c+中copy()函数有什么用,用到什么头文件

  对于头文件,有以下几个好处,你可以参考下

  1,头文件可以定义所用的函数列表,方便查阅你可以调用的函数;

  2,头文件可以定义很多宏定义,就是一些全局静态变量的定义,在这样的情况下,只要修改头文件的内容,程序就可以做相应的修改,不用亲自跑到繁琐的代码内去搜索。

  3,头文件只是声明,不占内存空间,要知道其执行过程,要看你头文件所申明的函数是在哪个.c文件里定义的,才知道。

  4,他并不是C自带的,可以不用。

  5,调用了头文件,就等于赋予了调用某些函数的权限,如果你要算一个数的N次方,就要调用Pow()函数,而这个函数是定义在math.c里面的,要用这个函数,就必需调用math.h这个头文件。

  1. 包含以下头文件:

  #include 《algorithm》

  2. 含义:

  output_iterator copy( input_iterator start, input_iterator end, output_iterator dest );

  The copy function copies the elements between start and end to dest. In other words, after copy has run,

  *dest = *start

  *(dest+1) = *(start+1)

  *(dest+2) = *(start+2)

  。。。

  *(dest+N) = *(start+N)

  The return value is the position in the destination range after the last element copied (i.e. dest+N+1)。 copy runs in linear time.

  3. 程序举例:

  For example, the following code uses copy to both copy the contents of one vector to another and to display the resulting vector:

  vector《int》 from_vector;

  for( int i = 0; i 《 10; i++ ) {

  from_vector.push_back( i );

  }

  vector《int》 to_vector(10);

  copy( from_vector.begin(), from_vector.end(), to_vector.begin() );

  cout 《《 “to_vector contains: ”;

  copy( to_vector.begin(), to_vector.end(), ostream_iterator《int》( cout, “ ” ) );

  cout 《《 endl;

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分