У вас написано:
«и очередное слагаемое оказалось по модулю меньше чем e»
в коде «s = s + Math.Pow(-1, i + 1) / i * (i + 1) * (i + 2)»
в качестве слагаемого именно «Math.Pow(-1, i + 1) / i * (i + 1) * (i + 2)», а не сумма. Плюс, действительно, как заметил carbon88, нужен модуль слагаемого, то есть примерно так (без учёта оптимизации) :
while( Math.Abs(Math.Pow(-1, i + 1) / i * (i + 1) * (i + 2)) < e)
{
…
}
Все не совсем так.
IntPtr не зря имеет такое название. По сути это либо число, либо указатель.
В контексте c++ переменная типа (char *) это указатель и она тождественна равна c# IntPtr. Другой вопрос как интерпретировать память на которую указывает этот указатель.
Если строка в c++ не меняется (тип const char *) то ей можно сопоставить c# string. Соответствующие преобразования выполнит компилятор.
Если же строка в c++ будет меняться, то тут нужно использовать работу с указателями и выделять память либо в с++ либо в c#.
Помимо этого нужно учитывать, что тип char в c++ означает однобайтовый символ, а char в c# это юникодный двух или четырехбайтовый символ. Поэтому нужны дополнительные атрибуты для преобразования Ansi-Unicode. При современном программировании, если нет особых указаний, нужно использовать юникодные символы. Им соответствует c++ wchar_t.
А теперь практика:
Тестовая функция прибавит к первой строке вторую. Максимальный размер первой строки (то есть размер выделенного буфера) указывается в третьем параметре.
C++:
extern "C" __declspec(dllexport)
void __stdcall TestString(wchar_t * str1, const wchar_t* str2, size_t str1len)
{
wcsncat(str1, str2, str1len);
return;
}
C# Пример немного усложнён для показа некоторых дополнительных возможностей по преобразованию строк.
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern void TestString(IntPtr str1, string str2, IntPtr str1len);
string TestConcat(string str1, string str2)
{
// Выделяем буфер для склеивания строки во внешней функции
var pStr1 = Marshal.AllocHGlobal(4096);
// Формируем массив байт соответствующий строке str1
var data = Encoding.Unicode.GetBytes(str1);
Marshal.Copy(data, 0, pStr1, data.Length);
// Теперь у нас в памяти по указателю pStr1 выделено 4096 байт и записана строка str1
// Вызов внешней функции
TestString(pStr1, str2, new IntPtr(4096));
// Теперь декодируем полученный результат.
var result = Marshal.PtrToStringUni(pStr1);
// Обязательно освобождаем выделенную память
Marshal.FreeHGlobal(pStr1);
либо так:
public static extern string TestString(string str1, string str2);
либо так:
public static extern string TestString(IntPtr str1, IntPtr str2);
Дальше. В с++ программе ошибка. Так нельзя делать. У вас массив str объявлен локально. Поэтому после выполнения функции TestString он пропадёт. В debug это незаметно, то в release память очистится и будет исключение.
В идеале нужно память выделить в программе на C# через Marshal.AllocHGlobal, в программе на c++ писать в эту память, а потом, после использования результата освободить память через FreeHGlobal.
Если под IntPtr понимается LPWSTR, то два варианта. Либо также применить к возвращаемому значению Marshal.PtrToStringUni и получишь строку, но гораздо проще сразу описать во внешней функции тип возвращаемого значения:
[DllImport("mydll.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static extern string MyFunc();
так сложно из-за того, что внешняя dll требует указатель на область памяти не только на чтение, но и на запись. При таком подходе явно видно с какой памятью работает внешняя dll.
Не перепутал. Программа которая пишет в файл указывает в этом параметре, что она не возражает, если кто-то во время её работы будет читать файл. Поэтому она указывает FileShare.Read. Можно вообще разрешить множественное изменение файла — когда несколько программ одновременно пишут в разные концы файла, тогда каждая из них должна открывать файл с параметром FileShare.ReadWrite.
Когда программа чтения открывает файл, то она не должна возражать ни против чтения, ни против записи в файл, поэтому она должна указать FileShare.ReadWrite. Если она укажет только FileShare.Read, то программа записи не сможет открыть одновременно этот файл для записи, а если она уже его открыла, то программа чтения не откроет в этот момент файл на чтение.
Это зависит от типа блокировки и объекта к которому она применяется — нужно ознакомиться с теорией про режимы изоляции и блокировки.
Может быть заблокирована строка, страница, где находятся обновляемые данные, таблица или вся база данных. Блокировки осуществляются автоматически при выполнении определённых действий (например, Update или Delete) или явного указания в запросе Select (UPDLOCK, ROWLOCK). Блокировки блокируют выполнение действий, требующих таких же блокировок из других транзакций. Только они должны работать в режиме изоляции не ниже READ COMMITTED, в твоём случае возможно нужен REPEATABLE READ.
for (double x = 0; x < 4; x += .05)
{
// вычисление значения нашей функции
double y = x * x;
// преобразуем к нашим координатам в зависимости от масштаба и расположения (значения указаны от балды)
var line = new LineSegment(new Point(x*20, (100 - y)*4), true);
fPath.Segments.Add(line);
}