拷贝函数出错(不是每次都会出错,偶尔会出错一次)实在不知道原因,
BOOL  CPublicFun::CopyChar(char *p1, const char *ps, int nMax)
{
BOOL bRe = TRUE;
int nlen = 0;
try {
nlen = strlen(ps);
if (nlen > nMax) nlen = nMax;
memcpy(p1, ps, nMax); // 这句出错,
p1[nlen] = '\0';
} catch (...) {
CString str;
str.Format("%d, %d, %s, %s", nlen, nMax, p1, ps);
AfxMessageBox(str);
bRe = FALSE;
}
return bRe;
}
nMax=30, sizeof(p1)=31,sizeof(ps) < 20,
出错那句由于不小心将nlen写成了nMax,但即使这样也不应该出错啊。只是读越界,并非写越界。
请各位帮忙指点一下这是为什么??

解决方案 »

  1.   

    glyc:有些内存不能读的,读到也会出错。我也有这种怀疑可没有实际证据,ps应该会跑到不能读的内存区域前面去吧。
    还有。出错之后,在catch中看到的状态居然全都是对的。
      

  2.   

    BOOL  CPublicFun::CopyChar(char *p1, const char *ps, int nMax) nMax必须=<sizeof(p1)
    ps必须=<sizeof(p1)
    p1必须不能指向完全属于自已的空间
      

  3.   

    如果ps没有\0,strlen就可能会异常(读异常)。
      

  4.   

    这几个条件都是满足的。当我把memcpy(p1, ps, nMax); 中的nMax改为nLen之后就不再出错了。
      

  5.   

    bool CopyStr(TCHAR * strDest, const TCHAR * strSour,UINT uMax)
    {
        if(!strDest || !strSour || !uMax)
           return false;    while(*strSour && uMax)
        {
           *strDest++ = *strSour ++;
           uMax --;
           
        }    if(*strSour)
        {
         *--strDest = _T('\0');
         return false;
        }
        else
         return true;
    }
      

  6.   

    BOOL  CPublicFun::CopyChar(char *p1, const char *ps, int nMax) nMax必须= <sizeof(p1) --------------//当我把memcpy(p1, ps, nMax); 中的nMax改为nLen之后就不再出错了。
    ps必须= <sizeof(p1) 
    p1必须不能指向完全属于自已的空间
      

  7.   

    strlen会异常这点忽略了。问题不是出在这里,我跟踪了每次出现异常都是在memcpy这里
      

  8.   

    BOOL  CPublicFun::CopyChar(char *p1, const char *ps, int nMax) 

    BOOL bRe = TRUE; 
    int nlen = 0; 
    try { 
    nlen = strlen(ps); 
    if (nlen > nMax) nlen = nMax; 
    if (nMax > strlen(p1)) nMax = strlen(p1);//加一句!!!!!!!!!!!
    memcpy(p1, ps, nMax); // 这句出错, 
    p1[nlen] = '\0'; 
    } catch (...) { 
    CString str; 
    str.Format("%d, %d, %s, %s", nlen, nMax, p1, ps); 
    AfxMessageBox(str); 
    bRe = FALSE; 

    return bRe; 

      

  9.   

    nMax必须= <sizeof(p1) --------------//当我把memcpy(p1, ps, nMax); 中的nMax改为nLen之后就不再出错了。 
    sizeof(p1)是定义为31的数组,nMax是传的一个常量,值为30,我想这想应该是满足的吧。因为ps的实际长度总是小于nMax的,而我每次都让它拷的nMax个。这个会不会有关系
      

  10.   

    BOOL  CPublicFun::CopyChar(char *p1, const char *ps, int nMax) 

    BOOL bRe = TRUE; 
    int nlen = 0; 
    try { 
    if (nMax > strlen(p1)) nMax = strlen(p1);//加一句!!!!!!!!!!! 前面写错了,应加在这儿
    nlen = strlen(ps); 
    if (nlen > nMax) nlen = nMax; 
    memcpy(p1, ps, nMax); // 这句出错, 
    p1[nlen] = '\0'; 
    } catch (...) { 
    CString str; 
    str.Format("%d, %d, %s, %s", nlen, nMax, p1, ps); 
    AfxMessageBox(str); 
    bRe = FALSE; 

    return bRe; 
      

  11.   

    因为ps的长度不一定有nMax大,所以可能会读ps越界。
      

  12.   

    因为ps的实际长度总是小于nMax的,而我每次都让它拷的nMax个。这个会不会有关系
    是这个问题,
    应该是memcpy(p1, ps, nlen ); // 这句出错,
      

  13.   

    因为是memcpy,如果用strcpy_s就没问题了。
      

  14.   

    因为ps的长度不一定有nMax大,所以可能会读ps越界。实际上ps的长度每次都小于nMax,如果说读ps越界,那应该是每次都出现吧。
      

  15.   

    这么改:
    nlen = strlen(ps); 
    if (nlen < nMax)
     nMax = nlen; 
    当然其实memcpy就用nlen作大小参数也可以。
      

  16.   

    cnzdgs:
    if (nMax > strlen(p1)) nMax = strlen(p1);//加一句!!!!!!!!!!! 前面写错了,应加在这儿 
    这句不能加,p1是被初始化为空的,加上这句一个字符都拷不进去了。
      

  17.   

    BOOL  CPublicFun::CopyChar(char *p1, const char *ps) 

       try
       {
          if(strlen(ps)>strlen(p1))
             memcpy(p1, ps, strlen(p1));
          else
             memcpy(p1, ps, strlen(ps));  
       }
       catch (...)
       {
          return false;
       } 
       return true; 

      

  18.   

    各位,我现在不是需要把它改对,而是想要知道为什么
    memcpy(p1, ps, nMax);这样写会有错误。可能是些什么样的原因引起的,而且还不能是每次都会引起异常的那种。
    我实际应用中ps长度绝对不会超过20,p1是个31的数组,nMax是个定值30。
      

  19.   

    现在是ps的问题,假设ps内存块的长度是20,而nMax是30,memcpy(p1, ps, nMax)就会导致访问ps越界,如果ps[20]~ps[30]不可读,就会产生读异常。
      

  20.   

    实际上你的CPublicFun::CopyChar这个函数要实现的功能就是strcpy_s。
      

  21.   

    char c[31];
    CString str = "sfdsfd";
    CString str1 = "sfdsfsfdsfsdfsdfsdfdsfsdfsdfsdfsdfd";
    CString str2 = "sfdsfsdfdsfdffffffffffffffffffffffd";
    CopyChar(c, (LPTSTR)(LPCTSTR)str, 30);
    CopyChar(c, (LPTSTR)(LPCTSTR)str1, 30);
    CopyChar(c, (LPTSTR)(LPCTSTR)str2, 30);ps小于30之后没事,我觉得很有可能ps之后的字符是不可读的。
      

  22.   

    嗯。lstrcpyn函数也能实现这个功能。
      

  23.   

    越界读内存在DEBUG下可能会异常...
    Release下面不会有事
      

  24.   

    CString strInfo = "";
    ST_MODULE stInfo; strInfo.Format("Select * from BoardType where DeviceType=%d order by Code", theApp.m_nDeviceType);
    if (pDB == NULL) {
    pDB = &m_Myado;
    }
    if (pDB->DoSQL(strInfo)) {
    while (!pDB->m_Rst->adoEOF) {
    strInfo = pDB->GetStr(2); // 名称
    // TRACE("\n%s", strInfo);
    stInfo.uType = (UCHAR)pDB->GetLongField(4); // 类型代码
    if (!m_PubProc.CopyChar(stInfo.Name, (LPTSTR)(LPCTSTR)strInfo)) {
    AfxMessageBox(strInfo);
    } // 添加取数据存储区
    SetType(&stInfo); memset(&stInfo, 0, sizeof(ST_MODULE));
    pDB->m_Rst->MoveNext();
    }
    pDB->m_Rst->Close();
    }if (!m_PubProc.CopyChar(stInfo.Name, (LPTSTR)(LPCTSTR)strInfo)) 
    就是调用的那个拷贝函数
      

  25.   

    我这个是debug版本,读越界不是每次都会提示异常?
      

  26.   

    说了半天LZ还是没懂。
    CString中的字符串是用new分配的内存,当字符串长度为20时,分配的内存长度通常是21,当执行memcpy时,由于指定的nMax是30,所以要复制30字节的数据,这就需要访问超过第21个字符之后的内存,也就是越界了,如果所访问的内存已经分配给了其它地方,访问就不会有问题,如果所访问的内存没有分配(这里的分配指的是虚拟内存页),就会产生读异常。这种内存越界引起读异常发生的几率不高。