C语言,指针与内存分配

指针变量与内存分配

1. char * str1;
//str1 只是一个指针,指针指向的空间还没有分配,所以此时用strcpy向str1所指向的内存
中拷贝内容将出错。利用malloc动态分配指向的内存(在堆中):
str1=(char *)malloc(10) or str1=(char *)malloc(sizeof(char) *num)//分配num个char
所占有的字节(一般是1个字节)数空间,用完后必须用free释放内存空间。这与在栈中自动
分配的内存不同,栈中的内存在函数结束后自动释放。


2.char str2[10];//字符数组的赋值要么在声明时初始化(="dfdf"or={'a','b','c','d'},要末一个字符的赋值,str[0]= ;str[1]= ;......或者strcpy(str2,"aaaaaa")(因为内存空间已分好);
如果char str2[10];str2="abcdefgjk";就会出错,因为str2表示数组str2[10]的首地址,在声明数组时已经分配好了地址值,不是变量,而是常量。strcpy(str2,"aaaaaa")这种数组初始化方式,是将"aaaaaa"拷贝到以str2为开始地址的内存空间当中。


3。
    char*str1;
    charstr2[10]="dfdf";
       str1=str2;
//将指针str1指向以str2为首地址的内存空间,即现在str2和str1表示内存中的同一区域.


4。char * str3="aaaaaaaaaaaaaaa";
   char * str2="bbbb";
   strcpy(str3,str2);
//这时的str2和str3就不指向同一内存空间,因为str3在初始化时已经分配了指向的内存空间;此时只是将str2所指向的内存的内容拷贝到str3所指向的内存空间的内容(注意:str3指向的内存空间的大小最好大于str2所指向的内存空间的大小,否则,可能将其他变量的内存覆盖。另外,c语言对数组不做越界检查,使用时候小心,否则出现不可预料的错误)。


5。其它如int,double,float,short等类型,在申明变量时内存空间就已经分配好了。例如:
    inti=1;
    int j;
    j=i;
    j=2;
   printf("i=[%d];j=[%d]\n",i,j);
输出结果为i=1;j=2


6。面向对象编程例如java中的对象声明,句柄和指针的情况类似
    Object myObj= NEW   Object()
   对象句柄myObj指向New在内存中创建的实例
   声明了对象以后必须实例化,才能调用对象的方法。
    ObjectAyouObj=New ObjectA();
   
   myObj=youObj//myObj和youObj同时指向ObjectA的实例

 

7.图例:

char*str1="abcd",*str2="cde";//"abcd"的首地址为2000,"cde"的首地址为2004,分别存放在str1和str2.
   
   address(int类型) address(int类型)strings or object

       ------                       ------
str1   |2000|  -----------------2000|   |: memory1
   ------                        ...
str2   |2004|  -----------------2004|   |: memory2
   ------                        ...
                           2007|    |
   ------                       ------
                                  |
   ------                       ------
(1)    str1=str2;         //str1的值变为2004,指向了memory2
(2)   strcpy(str1,str2);//将memory2的内容"cde"拷贝到memory1,str1仍指向memory1
kdsj\0fkdjfkdj\0fkdjfkjdfk\0
               

8.总结:
   内存的地址是固定的,而地址所指向的内存中的内容是变化的
   指针是存放地址的变量;
   strcpy是内存区域中的内容的拷贝,而内存的地址是固定不变的。
    字符数组charstr[10];与 char *str;的区别:
   
   字符数组在变量声明时即已分配了内存空间,也就是说他的地址已经确定了,而字
   符指针没有指向内存空间(除了char *str="dfdf")。
   字符数组中str表示数组的首地址,是一个常量,str等于一个固定的内存地址,所
   以永远不能在等号左边被赋值(除了声明变量初始化时,char str[10]="sssssss"),
   只能利用strcpy来改变他所指向的内存空间的内容。
   
    而char*str中str是一个变量,可以指向任意内存空间,;str=str2只表示将str指向
   地址str2指向的内存空间;他同样必须用strcpy来改变str所指向的内存区域的内容。
   注意:指针仅仅起指向的作用!!
   最常见的例子是:
       fgets(str,1000,fp);//预先定义str为字符数组char str[1000],
   因为不确定文件的一行有多长
       fetch into :str;//同上

   
9. C语言函数中的局部变量的空间一般都是放在堆栈里面.在进入函数前,通过"SUBSP,+XX"来为这些局部变量分配堆栈空间.然后同样通过BP来对这些局部变量进行访问.函数结束时,"MOVSP,BP"还原堆栈指针,局部变量随之而消失.最后以"POP BP"还原BP,结束该函数.

值得注意的是,C语言会自动为C函数中经常使用int类型变量设置成resigterint.这样的局部变量就不是使用堆栈空间的了,而就是直接使用SI寄存器.


10.    charstr[10];
    structaa   bb;
   ........
   memset(str,'\0',sizeof(str));//清空内存,赋值为10个'\0'字符
   memset(&bb,0,sizeof(struct aa));
   从文件中逐行读取,可以处理完一行,memset一下,再读取下一行
   
     strcat(str1,str2);//也要注意str1最好是定长的数组,如果是指针还要初始化,还要
长度。
   字符串比较大小只能用strcmp,strncmp
   strcmp(str1,str2)//   =0相等,否则不等
   strncmp(str1,str2,n)//   比较str1和str2的前n个字符
   函数:   
   atoi//将字符串转为整数
    char*itoa(int value, char *string, int radix); //将整数转为字符串


11.注意:char *str1;
    str1=(char*)malloc(sizeof(char) * num)
   给指针分配他所指向的内存空间的大小,sizeof函数是取得变量类型或者变量所占用
   的内存字节数。例如:   
   sizeof(int)//结果为4(个字节)
       sizeof(double)//结果为8(个字节)
       char str[]="qqqqqq";sizeof(str)//结果为7(个字节),不要漏掉'\0'!!!
       char*str="qqqqqq";sizeof(str)//结果为4(个字节)(32为操作系统),因为str是指针变量!!!
       
注意:指针变量(存放地址的变量)的sizeof值一般都为4,不要将所占用内存大小和字符串
      长度混淆!!!
      例如:char str[10]={'a','b','c'};
              strlen(str)//值为3
              sizeof(str)//值为10
              sizeof(char) * strlen(str)//值为3
          
      C语言中数组定义几位,元素的最大个数就是几位。例如char str[10];元素的最大个数
      为10,只不过字符数组自动在最末尾加'\0',所以定义字符数组的时候要小心,你想定
      义一个有2个字符的数组,就要char str[3];,留出一位给'\0',strlen为2,sizeof为
      3!!!!


12. return语句不可返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被
   自动销毁。但是可以return一个在“栈内存”的整型变量,因为返回的是内存中的值。
    例如
    char *Func(void)
    {
       char str[] = “helloworld”;    //str的内存位于栈上
       .......
       return str;//函数结束时候str为首地址的内存即刻释放,只是返回一个内存的地址                 
    }
    main()
      char*str1;
       str1=Func;
       printf("%s\n",str);// 将导致错误
    
   
13。内存分配方式有三种:

(1)静态内存分配。在内存的数据区上创建。内存在程序编译的时候就已经分配好。

   这块内存在程序的整个运行期间都存在。例如 已经初始化的变量,全局变量,static变量。
   
(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数
   执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率
   很高,但是分配的内存容量有限。也属于动态内存分配

(3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,
程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,
但问题也最多。
按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.
  静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变数据结构(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.
  栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。
  静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放.


    参考:永远的UNIX高质量C++-C编程指南 -- 第7章 内存管理 (1)
7.4指针参数是如何传递内存的?
      如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例7-4-1中,Test函数
      的语句GetMemory(str, 200)并没有使str获得期望的内存,str依旧是NULL,为什么?

void GetMemory(char *p, int num)
{
    p = (char*)malloc(sizeof(char) * num);
}
void Test(void)
{
    char *str =NULL;
   GetMemory(str,100);    // str仍然为 NULL
    strcpy(str,"hello");   // 运行错误
}

示例7-4-1 试图用指针参数申请动态内存

毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p=p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例7-4-2。

void GetMemory2(char **p, int num)
{
    *p = (char*)malloc(sizeof(char) * num);
}

void Test2(void)
{
    char *str =NULL;
   GetMemory2(&str, 100); // 注意参数是&str,而不是str
    strcpy(str,"hello");  
   cout<< str<< endl;
   free(str);
}

示例7-4-2用指向指针的指针申请动态内存

由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。这种方法更加简单,见示例7-4-3。

char *GetMemory3(int num)
{
    char *p =(char *)malloc(sizeof(char) * num);
    returnp;
}
void Test3(void)
{
    char *str =NULL;
    str =GetMemory3(100);
    strcpy(str,"hello");
   cout<< str<< endl;
   free(str);
}

示例7-4-3 用函数返回值来传递动态内存

用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见示例7-4-4。
char *GetString(void)
{
    char p[] ="hello world";
    returnp;   // 编译器将提出警告
}

void Test4(void)
{
char *str = NULL;
str = GetString(); // str 的内容是垃圾
cout<< str<< endl;
}

示例7-4-4 return语句返回指向“栈内存”的指针

用调试器逐步跟踪Test4,发现执行str =GetString语句后str不再是NULL指针,但是str的内容不是“hello world”而是垃圾。
如果把示例7-4-4改写成示例7-4-5,会怎么样?

char *GetString2(void)
{
    char *p ="hello world";
    returnp;
}

void Test5(void)
{
    char *str =NULL;
    str =GetString2();
   cout<< str<< endl;
}

示例7-4-5 return语句返回常量字符串

函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“helloworld”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。

14.函数参数的传递分为:值传送和引用(指针)传送。前者将变量的复本传给函数的形参,形参的改变不会引起变量原值得改变;后者将变量的地址传给形参,形参的改变将引起变量的改变。

======================================================================================

2003-3-21 20:29

1.    intfflush(FILE *stream);

清除输入流的缓冲区,使它仍然打开,并把输出流的缓冲区的内容写入它所联系的文件中。成功时返回0,出错时返回EOF。
   例如:fflush(stdout);//刷新屏幕输出
         FILE *fp;
         fputs(str,fp);
         fflush(fp);//马上写入文件中
       
2.    sprintf(filename,"%s/SFDJERR%s.%d",getenv("PRINTERDIR"),SF_sc.jgbm,SF_sc.wtjg);

3.    void sf_err(struct sf_dktable *sf_dk1,int flag)
      fprintf(fp,"委托机构[%s] 合同号[%s] 银行帐号[%s] 流水号[%d] 取款金额[.2f] \
      取款成功退款失败\n",sf_dk1->wtjg,sf_dk1->hth,sf_dk1->zh,sf_dk1->qkwdlsh,\
      sf_dk1->qkje);
      //注意:结构指针的写法

2003-3-22 9:21

1.再次重申:如果函数的参数是指针,千万不要用该指针申请动态内存。

2003-3-23 17:55
1.   exit退出整个程序;return退出所在的函数

2.    (1)cc-c mm.c
    ar r libmm.amm.o//编译静态连接库,2步走
   静态连接库是在编译的时候将函数库连接进程序
   如何调用静态连接库:
       cc -o nn nn.c -L/usr/work/lib -Bstatic -lmm
       //其中-Bstatic可以省略
           
    (2)cc -dy-G -o libmm.so mm.c
    另外,再加上-KPIC后可以提高内存的使用率
   //编译动态链接库,它是在程序启动的时候才连接需要的函数
   
   所以利用动态链接库的程序比静态链接库要小得多
   
    需要的环境变量:(注意:不要忘记设)
   LD_LIBRARY_PATH:增加链接程序搜索路径。
   LD_RUN_PATH:指定动态链接程序的搜索路径。
   例如:LD_LIBRARY_PATH=/usr/work/lib;export LD_LIBRARY_PATH
   
   如何调用libmyfun.so:
       cc -o mm mm.c -L/usr/work/lib -Bdynamic -lmyfun
   LD_LIBRARY_PATH必须设置,否则运行mm的时候找不到libmyfun.so!!!
   
   察看程序调用了哪些动态链接库利用ldd:   
       ldd mm   输出入下:
       dynamic linker: nn: file loaded: /usr/work/zzy/libmyfun.so
       dynamic linker: nn: file loaded: /usr/lib/libc.so.1
       
       
2003-3-24 8:59

1.    char*str1;
    char*str2;
   if(str1==str)//这种写法正确,它是指str1和str2指向了同一块内存,即地址相等       ...
   
   
    if(strcmp(str1,str2)==0)//它是指str1和str2所指向的内存中的内容相等
   
       ...
       
2003-3-31 21:39

1.   全局变量和静态全局变量只能在程序的开始初始化一次。非静态局部变量在进入定义
   他们的程序块的每个入口多次初始化。静态局部变量也只初始化一次。
   静态变量分为:静态全局变量和静态局部变量
   静态全局变量只在他所在的文件中生存,别的文件不可以用extern声明他
   静态局部变量只在两个函数之间跳转,虽然超过作用域,但是这个变量的生存期为整
    个程序。
   变量的存储方式;
           extern
           register
           static
           auto
   函数存储默认为extern   
2.    char*str="abc";
   printf("%d\n",str);//打印地址
   printf("%s\n",str);//打印字符串
   
3.? 初始化数据段。通常将此段称为数据段,它包含了程序中需赋初值的变量。例如, C程
序中任何函数之外的说明:
int maxcount = 99;使此变量以初值存放在初始化数据段中。

一般是:全局变量和静态变量
? 非初始化数据段。通常将此段称为b s s段,这一名称来源于早期汇编程序的一个操作符,
意思是“block started by symbol(由符号开始的块)”,在程序开始执行之前,内核将此段初始
化为0。函数外的说明:
long sum[1000] ;
使此变量存放在非初始化数据段中。
? 栈。自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次函数调用时,
其返回地址、以及调用者的环境信息(例如某些机器寄存器)都存放在栈中。然后,新被调
用的函数在栈上为其自动和临时变量分配存储空间。通过以这种方式使用栈, C函数可以递归
调用。
? 堆。通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于非初始化数据段顶
和栈底之间。

   

   

   未初始化的数据----由exec 赋初值

   初始化的数据------由exec从程序文件中读到

   正文--------------由exec从程序文件中读到          

 

注:平常所说的堆栈即为栈(stack)
   
2003-4-2 20:58

1.    函数名:memset
    功 能:设置s中的所有字节为ch, s数组的大小由n给定
    用 法: void*memset(void *s, char ch, unsigned n);
   
2.    函数名:memcpy
    功 能:从源source中拷贝n个字节到目标destin中
    用 法: void*memcpy(void *destin, void *source, unsigned n);
   
   他同strcpy的区别就是memcpy可以给结构赋值:
       struct JieGou jg1;
       struct JieGou jg2;
       memcpy(jg1,jg2,sizeof(struct JieGou));
       
2003-4-24 9:44

1.    char*str1="abcd";
   此时分配的内存既不在栈中,也不在堆中,而是在静态存储区域。
    charstr2[]="dfdfdf";
   //这是的内存在栈中
   
2.   在用delete或用free释放指针p所指的内存后,只是p所指的内存释放了。变量p还是存在的。
   应该马上显式地将p置为NULL,
   以防下次使用p时发生错误。示例程序如下:if(p==NULL);strcpy(p,"dkfjdf");//
   //p是个野指针,指向了一堆垃圾
“野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,
因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。
“野指针”的成因主要有两种:

(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,
它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向
合法的内存。例如

    char *p =NULL;
    char *str =(char *) malloc(100);

(2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。参见7.5节。

   
3.   不要将BOOL值TRUE和FALSE对应于1和0进行编程。大多数编程语言将FALSE定义为0,
   任何非0值都是TRUE。Visual C++将TRUE定义为1,而Visual Basic则将
   TRUE定义为-1。示例程序如下:
   BOOL   flag;
   
   if(flag)       { // do something}    //正确的用法
   if(flag==TRUE)   { // do something}       // 危险的用法
   if(flag==1)       { // do something}    //危险的用法
   if(!flag)       { // do something}    //正确的用法
   if(flag==FALSE) { // do something}       // 不合理的用法
   if(flag==0)       { // do something}    //不合理的用法

(4)小心不要将"= ="写成"=",编译器不会自动发现这种错误。
(5)不要将123写成0123,后者是八进制的数值。
(6)将自己经常犯的编程错误记录下来,制成表格贴在计算机旁边。

4.   以下是我编程时采用的命名约定:
(1)宏定义用大写字母加下划线表示,如MAX_LENGTH;
(2)函数用大写字母开头的单词组合而成,如SetName, GetName ;
(3)指针变量加前缀p,如 *pNode ;
(4)BOOL 变量加前缀b,如 bFlag ;
(5)int    变量加前缀i,如 iWidth ;
(6)float 变量加前缀f,如 fWidth ;
(7)double变量加前缀d,如 dWidth ;
(8)字符串变量加前缀str,如 strName ;
(9)枚举变量加前缀e,如 eDrawMode ;
(10)类的成员变量加前缀m_,如 m_strName, m_iWidth ;
对于 int, float, double 型的变量,如果变量名的含义十分明显,则不加前缀,避免烦琐。
如用于循环的int型变量 i,j,k ;float 型的三维坐标(x,y,z)等。


2003-5-13 15:12

1.   传址参数,交换a,b的值必须用传址。另外还有传值,传引用。
#include <stdio.h>
main()
{
int a=10;
int b=20;
printf("a is %d b is %d\n",a,b);
swap(&a,&b);
printf("a is %d b is %d\n",a,b);
}

swap(int *a,int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}

2003-5-22 17:23

1. 在运用宏__FILE__和__LINE__时,要注意,不要写在一个函数里,在其他地方调用此函数
最好写在如下:
#define ERR  printf("error:[%d]file:[%s]line:[%d]\n",\
sqlca.sqlcode,__FILE__,__LINE__);exit(0);   
如果写在函数里,比如:
void err()
{
   printf("error:[%d]file:[%s]line:[%d]\n",sqlca.sqlcode,__FILE__,__LINE__);
}
会造成这样一种情况:
   __LINE__的值永远是此函数中printf语句所在的行数
   
2003-5-28 15:30

1.strcpy与memcpy的区别

strcpy(str1,str2)是将str2连带'\0'一同拷贝到str1,比如:str1="aaaa",str2="bbb",
则结果str1="bbb",导致str1碰到'\0',自动终止字符串

memcpy(str1,str2,strlen(str2))是将str2的bbb(不带'\0')拷贝到str1中,结果为
str1="bbba"

这里注意:strlen(str2)=3    sizeof(str2)=4  所以如果不想覆盖str1中其余的字符,
则不能用sizeof.
strncpy与memcpy功能一样。
2005-04-12

1.跨平台申请内存
malloc(sizeof(char)*(strlen(str)+1))

char str[]="hello world";
char str1[9]
这两种情况sizeof(str)=12;sizeof(str1)=9;strlen(str)=11;strlen(str1)=0;
char *p=str;
sizeof (p)=4
如果将str[]用作参数例如fun(char str[100])
则sizeof(str)=4而不是100,因为此时字符串数组自动退化为指针。

2.char *str = "ABCD";
str[0]='M';//将导致错误,因为这种方式是在静态存储区分配内存
如果用strcpy(str,"BBBB")会出错,因为char *str没有动态分配内存,而是指向

了静态存储区如果写成:char *str = (char *)malloc(100)
strcpy (str,"ABCD");
str[0] = 'M';即可

char str[4] = "ABC";
str[0]='N';
则str = "NBC";因为是在栈上分配内存

3.new 必须与delete对应,动态内存必须要手工释放,动态内存分配的析构函数只会在使用delete的时候被调用。

4.如果文件中的记录格式为定长,长度为99,则定义char*strBuf[101]//99+'\n'+'\0';fgets(strBuf,101,fp)从fp中读取100个字符包括\r,都作为一个字符串,最后以'\r'结束(fgets中读取字符串的长度是101-1),这样输出到另一个文件的时候fprint(fp1,"%s",strBuf)自动回车,不用在%s后加\n
如果用fread(strBuf,100,1,fp)这样的写法即可。但是之前必须执行

memset(strBuf, '\0',sizeof(strBuf))否则,会出现很乱的字符,而fgets不存在这个问题,不知道为什么。总之,在使用字符串之前,最好memset一下。

无论用fgets还是fread读取的文件的记录结果strlen(strBuf)不是99,而是100。
另外:int fread(void *buf, int size, int count,FILE*stream)表示从文件中读取count(字段数)个字段,每个字段大小为size,函数返回实际读取的字段数。如果函数要求的字段数超过实际文件存放的字段数,举例说明:

文件内容如下:

AAAAAAAAAA
AAAAABBBBB
AAAAA

while(fread(strBuf,11,1,fp))
{
   printf("str=[%s]\n",str);
}

如果用fread读文件while(fread(strBuf,11,1,fp))只能读两条出来,前两条返回1,第三条返回0。因为第三条只有6个字节(连着回车符),不满足长度为11的条件,所以fread读文件的话,最实用于定长文件。但是第三条fread也将值赋给了strBuf,只是不满足条件返回了0。第三条的格式:

(1)没有memset(str,'\0',sizefo(str))

[AAAAA(此处一个回车符)
BBBB(此处一个回车符)--这部分是上一个串留下的部分
]

(2)有memset(str,'\0',sizefo(str))

[AAAAA(此处一个回车符)

]

在例如:

AAAAAAAAAA
AAAAA
AAAAAAAAAA
这种情况会跨行截取11个字节,第一条正常,第二条就变为:

[AAAAA(此处是一个回车符)

AAAAA]

如下例所示:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main()
{
int i =0;
FILE *fp,*fp1,*fp2;
char str[10]="370706751";
char str1[11];

memset(str1,'\0',sizeof(str1));
fp = fopen("d:\\test.txt", "w");
if (fp == NULL)
{
   printf("create fileerror!\n");
   return -1;
}
//fwrite("a\0b",3,1,fp);
fprintf(fp, "%s\n\0",str);
//fwrite("a\0b",3,1,fp);
fprintf(fp, "%s\n\0",str);

fclose(fp);

fp1 = fopen("d:\\test.txt", "r");
if (fp1 == NULL)
{
   printf("create fileerror!\n");
   return -1;
}
fp2 = fopen("d:\\test1.txt", "w");
if (fp2 == NULL)
{
   printf("create fileerror!\n");
   return -1;
}
while (fgets(str1,11,fp1) )
//while (fread(str1,10,1,fp1))
{
   i++;
   printf("%s",str1);
   fprintf(fp2,"%s",str1);
}
fclose(fp1);
fclose(fp2);
printf("record num = [%d]\n",i);
}

2005-06-16

c++中

Object object1 = new Object();
......
delete object1;
object1 = NULL;好的编程习惯,最后置为NULL,防止野指针,因为虽然内存释放了,但是指向一堆垃圾。

2005-06-18:

int main(int argc , char *arge[])
{
char str[]=" aaaaaaaaa\0bbbbb";
char str1[]=" aaaaaaaaa";

if (memcmp(str,str1,17) == 0)
   printf("xiangdeng\n");

    if(strncmp(str,str1,17) == 0)
   printf("--xiangdeng\n");
}

从上例可以看出strncmp和memcmp的区别,strncmp会截断字符串str与str1判断,所以输出相等,但是memcmp会将'\0'带入比较所以不相等。

同理,strncpy与memcpy的区别也一样。

int main(int argc , char *arge[])
{
char str[18]=" aaaaaaaaa\0bbbbb";
char str2[18];
strncpy(str2,str,17);
for (int i=0; i<17; i++)
{
   printf("str2[%d]=[%c]\n", i,str2[i]);
}
memcpy(str2,str,17);
for (int i=0; i<17; i++)
{
   printf("str2[%d]=[%c]\n", i,str2[i]);
}
}

memcpy会输出'\0'后面的bbbbb,而strncpy不会输出。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值