Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Как объяснить исключение при простом присваивании


Автор: Royan 2.7.2004, 21:48
Вот мой код:

Код
LPSTR CMyDoc::mMyTrim(LPSTR szStr){
 //MessageBox(NULL, szStr, "", MB_OK);
 
 size_t  nStrLen = 0;
 StringCchLength(szStr, 4096, &nStrLen);
 LPSTR szTemp = new CHAR[nStrLen+1];

 StringCchCopy(szTemp, nStrLen, szStr);
 szTemp = szStr + nStrLen -1;


 //  First trim spaces on the right
 while( (szTemp >= szStr) && (*szTemp == ' ') )
   *szTemp = '\0';//Здесь и возникает ошибка


Переменная szStr приходит из WinMain (это lpCmdStr). На самом деле в том месте где происходит присваивание, *szTemp точно содержит пробел, то есть * не разывеновывает указатель на не проинициализированную область памяти, соответственно и присваивание тоже законно, но по какой-то причине именно в этом месте вылетает исключение

Автор: Nimbus 4.7.2004, 15:41
IMHO, видимо, проблема заключается вот в этой строке:
Цитата
szTemp = szStr + nStrLen -1;

Объясняю, почему:
в строке
Цитата
LPSTR szTemp = new CHAR[nStrLen+1];

была выделена память в области динамического обмена, указатель szTemp содержит теперь АДРЕС начала выделенной области памяти. Затем, в строке
Цитата
szTemp = szStr + nStrLen -1;

этому указателю присваивается адрес хр$н знает какой области памяти, которая, кстати, может быть УЖЕ использована для других целей!
...и затем, в эту хр$н знает какую область памяти, ты записываешь в строке
Цитата
*szTemp = '\0';

символ окончания строки '\0' !!!
По твоему, это корректно???

Автор: p0s0l 4.7.2004, 18:05
Цитата
этому указателю присваивается адрес хр$н знает какой области памяти, которая, кстати, может быть УЖЕ использована для других целей!
А по-моему, у него всё нормально тут: szTemp присваивается адрес последнего ненулевого символа строки szStr...
Только не понятно - зачем там было создавать и копировать строку ?... Задумка не совсем ясна - надо обрезать исходную строку или же обрезать скопированную строку ?
У меня такой код обрезает справа пробелы в szStr нормально, без ошибок:
Код
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR szStr, int)
{
size_t nStrLen = strlen(szStr);
LPSTR szTemp = szStr + nStrLen -1;

//  First trim spaces on the right
while( (szTemp >= szStr) && (*szTemp == ' ') )
  *szTemp-- = '\0';
MessageBox (0, szStr, szStr, 0);
}
(добавил только --, чтобы все пробелы обрезались, а не только один последний)
PS: есть функция StrTrim...


Автор: Nimbus 4.7.2004, 23:55
Признаю, насчет
Цитата
этому указателю присваивается адрес хр$н знает какой области памяти, которая, кстати, может быть УЖЕ использована для других целей!

ПОГОРЯЧИЛСЯ, но постойте, куда же девался post от mr.DUDA (так, кажется, его зовут?) wink.gif

Автор: Олег М 5.7.2004, 10:50
[quote]LPSTR CMyDoc::mMyTrim(LPSTR szStr){
//MessageBox(NULL, szStr, "", MB_OK);

size_t nStrLen = 0;
StringCchLength(szStr, 4096, &nStrLen);
LPSTR szTemp = new CHAR[nStrLen+1];

StringCchCopy(szTemp, nStrLen, szStr);
szTemp = szStr + nStrLen -1;


// First trim spaces on the right
while( (szTemp >= szStr) && (*szTemp == ' ') )
*szTemp = '\0';//Здесь и возникает ошибка

Какой-то хитровыдуманный способ. Но впринципе дожно работать. Только здесь надо
Код
szTemp = szTemp + nStrLen -1;

и можно попрощаться с началом строки - хрен потом найдёшь. Ну да ладно.
И проверять надо, чтоб nStrLen!=0. И чтоб строка из одних пробелов не состояла - то начало-то потеряялось.
И цикл чуть-чуть переделать
Код

// while( /*(szTemp >= szStr)  один чёрт не срабатывает*/ && (*szTemp == ' ') )
//   *szTemp = '\0';//Здесь и возникает ошибка
while (*szTemp==' ') *(szTemp--)=0;

Атак всё круто. Иногда даже будет работать

Автор: AndyY 5.7.2004, 11:48
думаю действительно lpCmdStr лежит на страничке с атрибутами PAGE_READONLY и при попытке ее модифицировать и происходит exception.

надо не так:
szTemp = szStr + nStrLen -1;
а так:
szTemp = szTemp + nStrLen -1;

только начало строки действительно теряем

Автор: Royan 5.7.2004, 15:28
2Nimbus
Твоя мысль ясна и поэтому я несколько переделал алгоритм, дабы избавиться от подобных недорозумений, и хоть он получился несколько плосковатым, зато по-мойму стал более безопасным

2p0s0l
Ради одной функции StrTrim подрубать библу слишком жирно wink.gif

2Олег М
Насчет nStrLen!=0 согласен, но менять условия цикла я не стал, так как есть вероятность того что байт перед 0-м символом строки тоже окажется пробелом и тогда будем считать левые пробелы лежащие где - то там...

2AndyY
Цитата
думаю действительно lpCmdStr лежит на страничке с атрибутами PAGE_READONLY и при попытке ее модифицировать и происходит exception.

Не думаю, я в одном случае получаю строчку из "Configuration Properties > Debugging > Command Arguments" проекта, а второй раз из самой командной строки, а результат один и тот же.

Автор: Nimbus 6.7.2004, 00:07
И что, это работает?! wow.gif
Код
szTemp = szStr + nStrLen -1;

А где же тип переменной szTemp? ...хотя, если она была уже объявлена где-то...
И вот это ещё:
Код
int nLastPos = nStrLen;

В данном случае, IMHO, переменная nLastPos ВСЕГДА будет равна 0 (что-то я не просёк, где nStrLen присваивается хоть что-то после инициализации нулём). Но, как я подозреваю, задумка была совсем иной! hehe.gif
Остальное проверю завтра, а то поздно уже... rolleyes.gif

Автор: Nimbus 6.7.2004, 00:10
...да, похоже на сервере со временем что-то (на моих часах 01:11)???

Автор: Nimbus 6.7.2004, 00:12
...да, похоже на сервере со временем что-то (на моих часах 01:11)???

Автор: Олег М 6.7.2004, 08:47
Цитата
Вобщем вот в итоге что я изобрел:

Да уж, точно - изобрёл. Велосипед с треугольными колёсами. Ты её хоть скомпилировал? О запуске речи пока и не идёт

Автор: Royan 6.7.2004, 14:44
Прошу прощения вот правильный вариант (то что выше писалось на работе из головы поэтому и наделал ошибок)

Цитата
LPSTR CMyStrFormat::mMyTrim(LPSTR szStr){
 
 
if(szStr ==  0){
   
return '\0';
  }

  size_t nStrLen = 0;
//Total string length
 
 
StringCchLength(szStr, 4096, &nStrLen); 

  LPSTR szTemp = szStr + nStrLen -1;

  size_t nLastPos = nStrLen;

 
// Count spaces on the right
 
while( (szTemp >= szStr) && (*szTemp == ' ') ){
    szTemp--;
    nLastPos--;
  }

 
//If string contained only paces return '\0'
 
if(nLastPos == 0){
   
return '\0';
  }


  szTemp = szStr;
 
int nCurPos = 0;

 
// Now count spaces on the left
 
while (*szTemp == ' '){
    nCurPos++;
    szTemp++;
  }

 
//The lenght of the trimmed string
 
size_t nTrimmedStrLen = nStrLen - nCurPos - (nStrLen - nLastPos);
  szFormattedStr =
new CHAR[nTrimmedStrLen];

 
  VALID_GLE_EX(szFormattedStr ,"Not enough memory. Please close other applications and try again.",
false);
 

 
//Copy the resulting trimmed string

 
while (nTrimmedStrLen > 0){
    nTrimmedStrLen --;
    *szFormattedStr++ = *szTemp++;
  }

  *szFormattedStr = '\0';
//Terminating NULL character
 
szFormattedStr-=(nStrLen - nCurPos - (nStrLen - nLastPos));//Rollback to the begining of the string
 
return szFormattedStr;
}

Автор: Олег М 6.7.2004, 15:11
Нормально только надо {if(nLastPos == 0) { return ""; }

как вариант (тоже из головы) - почти тоже самое
Код
static TCHAR _szEmpty[]=_T("");
LPTSTR CMyStrFormat::mMyTrim(LPTSTR pszStr)
{
if (!szStr) return _szEmpty;

LPTSTR pszStart=pszStr,pszEnd;

for (;*pszStart==_T(' ');++pszStart);

int nLen;
StringCchLength(pszStart, 4096, &nLen)

for (psz1=pszStart+nLen;pszEnd!=pszStart && *pszEnd=_T(' '); --pszEnd);

if (pszStart==pszEnd) return _szEmpty;

nLen=pszEnd-pszStart;
TCHAR *pszRes=new TCHAR[nLen+1];
memcpy(pszRes,pszStart,nLen*sizeof(TCHAR));
pszRes[ nLen+1]=0;
return pszRes;
}



Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)