10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
1

Указатели и указатели на указатели, а также типы данных

16.11.2012, 12:46. Показов 3205. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Недавно начал изучать Си, перешел с Delphi.
Много непонятного и пока процесс идет медленно. Накачал литературы, буду изучать)
Щас хотелось бы узнать как решить следующую задачу:

Пишу DLL, в ней есть экспортируемая функция:
Код
void APIENTRY MtSrvManagerProtocol(ULONG ip, UserInfo *us, unsigned char *in_data, int in_size,unsigned char **out_data,int *out_size)
Что за тип **out_data ? Указатель на указатель? для чего такой может использоваться? и самое главное как его заполнить данными?

char *in_data
с горем пополам перевел в char
Код
char  temp[1024];
strcpy(temp,(char *)in_data)
и смог использовать, может есть лучше способ?

И мне нужно перевести in_data или temp перевести в LPCSTR, как это лучше сделать?

Спасибо.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.11.2012, 12:46
Ответы с готовыми решениями:

Через указатели на указатели посчитать сумму двух чисел и записать в третье
1. Через указатели на указатели посчитать сумму двух чисел и записать в третье. 2. Написать...

Почему Лафоре использует указатели на указатели, вместо обмена значениями указателей?
Доброго времени суток! Задался теоретическим вопросом. Читал пример из книги Лафоре...

Используя нетипизированные указатели и указатели на подпрограммы обобщить сортировку пузырьком
Смысл задания в том, что нужно отсортировать массив структур из 3х полей по сумме координат есть...

Есть три переменные. Используя указатели на указатели, поменять значение максимальной и минимальной переменной
Мой код. #include <iostream> #include <stdlib.h> #include<iomanip> using namespace std; ...

17
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.11.2012, 12:56 2
Цитата Сообщение от Duss Посмотреть сообщение
Указатель на указатель
это называется двойной указатель.
Цитата Сообщение от Duss Посмотреть сообщение
для чего такой может использоваться?
Ну во-первых через указатели на нулевые элементы реализуются массивы. А если элементы массива сами массивы? Получается, что массивы-элементы реализуются через указатели, а сам массив - массив указателей, но тоже реализуется через указатель. На что? Только на указатель же. Во-вторых через указатели реализуются изменяемые в самой функции параметры. А если при этом сам параметр - указатель? Или массив? Вот и получается двойной. Но тогда он может быть зщаменён ссылкой на указатель, да и вообще изменяемые параметры могут реализовываться ссылками вместо указателей.

Добавлено через 1 минуту
Цитата Сообщение от Duss Посмотреть сообщение
Что за тип **out_data ?
У тебя нет такого типа.
1
10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
16.11.2012, 12:57  [ТС] 3
Что за тип **out_data ?
У тебя нет такого типа.
Да, в смысле unsigned char **out_data.
Т.е. что такое unsigned char я понимаю, меня интересует зачем **.
А для чего нужен двойной указатель? Т.е. он указывает на память, в которой хранится указатель на unsigned char ?
Не совсем понимаю смысл этого.
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.11.2012, 13:09 4
Цитата Сообщение от Duss Посмотреть сообщение
char *in_data
с горем пополам перевел в char
перекосячил. Указатель в ча не переводится.

Добавлено через 3 минуты
Цитата Сообщение от Duss Посмотреть сообщение
char *temp[1024];
strcpy(temp,(char *)in_data)
Зачем? У тебя уже указатель на char. Зачем ещё один? К тому же это опасно переполнением массива, так как автоматический массив резервируется конкретного размера, а указатель подразумевает динамический, размер которого не известен.

Добавлено через 34 секунды
Цитата Сообщение от Duss Посмотреть сообщение
и смог использовать, может есть лучше способ?
Нет худшего.

Добавлено через 6 минут
Цитата Сообщение от Duss Посмотреть сообщение
И мне нужно перевести in_data или temp перевести в LPCSTR,
зачем?
1
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
16.11.2012, 13:21 5
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//Чтобы функция могла менять переменную, нужно передать ее в эту функцию по указателю или по ссылке. 
//Будем рассматривать случай с указателями:
 
void SetFive(int* ptr)
{
  *ptr = 5;
}
 
// в коде:
int value = 0;
SetFive(&value);
// вот тут значение value будет равно 5
 
 
 
// Теперь, если функция должна изменять указатель, то в функцию нужно передать указатель на указатель:
void Allocate(char** ptr)
{
  *ptr = new char[10];
}
 
// в коде:
char* p = 0;
Allocate(&p);
// вот тут p будет указывать на динамечески выделенный массив. p != 0;
 
 
//Аналогия с интом еще более наглядна, если сделать тайпдеф для указателя:
typedef char* CharPtr;
 
// в случае с интом аргумент имел тип int*,  а в нашем случае - CharPtr*
// т.е. сперва идет имя типа, а потом звездочка
void Allocate(CharPtr* ptr)
{
  // в случае с интом было *ptr = 5, а в этом случае так:
  *ptr = new char[10];
}
 
//в коде тоже все похоже на случай с интом.
//сперва объявляется переменная типа CharPtr и чтобы она изменилас,
//в функцию передается ее адрес
CharPtr ptr = 0;
Allocate(&ptr);
// тут ptr будет указывать на динамически выделенный массив.
1
10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
16.11.2012, 13:21  [ТС] 6
Ок, т.е. unsigned char *in_data - это массив чаров (строка),
а unsigned char **out_data это массив массивов чаров (массив строк).

Цитата Сообщение от taras atavin Посмотреть сообщение
зачем?
Есть функция записи в лог, она принимает LPCSTR, я бы хотел перевести char *in_data в LPCSTR и посмотреть что я получил то же что отправил или что-то другое)

Как мне заполнить out_data данными? в Delphi можно было указать размеры массива, если он безразмерный или размер определялся при объявлении.
Например я хочу в out_data засунуть 1 строчку
Код
 out_data[0] = in_data;
в принципе проходит, также заполняю out_size
Код
out_size[0] =in_size;
этого достаточно? Компилятор поймет что элемента out_data[1] нет или там может быть мусор?
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.11.2012, 13:30 7
Цитата Сообщение от Duss Посмотреть сообщение
Есть функция записи в лог, она принимает LPCSTR, я бы хотел перевести char *in_data в LPCSTR и посмотреть что я получил то же что отправил или что-то другое)
Передавай, как есть, это одно и то же.

Добавлено через 3 минуты
Цитата Сообщение от Duss Посмотреть сообщение
out_size[0] =in_size;
этого достаточно? Компилятор поймет что элемента out_data[1] нет или там может быть мусор?
Нет. Меня смущает out, возможно это выходные, то есть изменяемые параметры, тогда out_data - простой массив cahrов, а не массив массивов, а out_size - вообще не массив. Но в любом случае запись чего либо в нулевой элемент не говорит об остальных элементах.
0
10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
16.11.2012, 13:41  [ТС] 8
Цитата Сообщение от taras atavin Посмотреть сообщение
Нет. Меня смущает out, возможно это выходные, то есть изменяемые параметры, тогда out_data - простой массив cahrов, а не массив массивов, а out_size - вообще не массив. Но в любом случае запись чего либо в нулевой элемент не говорит об остальных элементах.
Да, так и есть.
В ин я получаю строку, в аут могу отдать строку, в некоторых случаях массивы строк.
Т.е. out_data должна быть массивом строк.
Т.к. это DLL я должен передать размер всего этого дела, для этого служит out_size

Добавлено через 1 минуту
DU Спасибо за примеры, вкуривю.

Добавлено через 2 минуты
Цитата Сообщение от taras atavin Посмотреть сообщение
Передавай, как есть, это одно и то же.
LogsOut: невозможно преобразовать параметр 3 из 'unsigned char *' в 'LPCSTR'
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
16.11.2012, 13:48 9
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
// Ошибка потому что
typedef char CHAR;
typedef const CHAR* LPCSTR;
//т.е. 
LPCSTR == const char*
 
//неявно преобразовывать unsigned char* в char* нельзя. это раные типы.
 
 
  unsigned char* p1 = 0;
  char* p2 = 0;
  p2 = p1; // ошибка
  p2 = (char*)p1; // ok. явное преобразование
1
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.11.2012, 13:49 10
Тогда передай
C++
1
(char *)in_data
, или
C++
1
(LPCSTR) in_data
.
1
10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
16.11.2012, 16:33  [ТС] 11
Во многом разобрался.
out_data - объявил как


Код
char buffer[256];
char *res = buffer;
int len;
Код
res = "wwwww";
out_data =  (unsigned char **)&res;
len = sizeof(out_data);
out_size = &len;
Переменные объявлены глобально, чтобы после выполнения функции они не уничтожались.
Но после вызова функции получаю эти значения пустыми.
Функция находится в ДЛЛ, вызываю ее не из самой длл.
Может глобальные переменные нужно где-то в паблике объявить?
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.11.2012, 16:50 12
Цитата Сообщение от Duss Посмотреть сообщение
Переменные объявлены глобально, чтобы после выполнения функции они не уничтожались.
Но после вызова функции получаю эти значения пустыми.
Функция находится в ДЛЛ, вызываю ее не из самой длл.
Может глобальные переменные нужно где-то в паблике объявить?
Паблик в глобале. Капец! Это же не член класса, а память другой программы, она должна быть экспортируемой. А лучше создавай в куче.

Добавлено через 8 минут
Причём, даже так: вызывающая программа:
C++
1
2
3
4
5
6
ULONG ip;
UserInfo us;
unsigned char in_data[16];
unsigned char *out_data;
int out_size;
MtSrvManagerProtocol (ip, &us, in_data, 16, &out_data. &outsize)
, функция:
C++
1
2
*out_data=new char [32];
*outsize=32;
. Обрати внимание, оба указателя функция получает, а не передаёт. В память по адресу из полученного двойному она присваивает простой указатель, а в память по адресу из полученного простого указателя пишет число.
0
10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
16.11.2012, 17:00  [ТС] 13
В том то и дело- вызывающая программа не моя.
Я к ней могу написать DLL плагин и подключиться через API и вызвать через него функцию MtSrvManagerProtocol
Т.е. спровоцировать ее вызов и получить результаты.

Как мне засунуть переменные out в кучу?
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.11.2012, 17:04 14
Тогда весь этот синтаксис там уже соблюдён.
0
10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
16.11.2012, 17:06  [ТС] 15
т.е. мне достаточно у себя в DLL объявить переменные глобально, чтобы у вызывающей программы был к ним доступ?
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
16.11.2012, 17:07 16
Цитата Сообщение от Duss Посмотреть сообщение
Как мне засунуть переменные out в кучу?
Одну переменную. size - обычная автоматическая переменная, только у тебя от неё не идентификатор, а только адрес и для записи нужна косвенная адресация. Это
Цитата Сообщение от taras atavin Посмотреть сообщение
C++
1
*out_data=new char [32];
и есть создание в куче.

Добавлено через 1 минуту
Цитата Сообщение от Duss Посмотреть сообщение
.е. мне достаточно у себя в DLL объявить переменные глобально, чтобы у вызывающей программы был к ним доступ?
Нет. Во-первых ты можешь только экспортировать, а не глобалить. А во-вторых откуда вызывающая программа узнает, как эти переменные зовут?
0
10 / 10 / 4
Регистрация: 14.01.2010
Сообщений: 80
16.11.2012, 17:20  [ТС] 17
[size="1"][color="grey"]откуда вызывающая программа узнает, как эти переменные зовут?[/QUOTE]

К вызывающей программе есть мануал, в нем сказано, что она вызывает функцию

MtSrvManagerProtocol

Синтаксис описан в .h файле


Код
void APIENTRY MtSrvManagerProtocol(ULONG ip, UserInfo *us, unsigned char *in_data, int in_size,unsigned char **out_data,int *out_size)
Добавлено через 6 минут
Цитата Сообщение от taras atavin Посмотреть сообщение
Одну переменную. size - обычная автоматическая переменная, только у тебя от неё не идентификатор, а только адрес и для записи нужна косвенная адресация. Это
Код
*out_data=new char [32];
и есть создание в куче.
Да, про кучу я почитал немного так тоже пробовал.
ругается:

отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
и
инициализация: невозможно преобразовать 'char *' в 'int *'

Добавлено через 2 минуты
я еще хотел res создать в куче
Код
res=new char [256];
а в out_data указатель на res отправить.
Код
ut_data =  (unsigned char **)&res;
0
4226 / 1795 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
17.11.2012, 22:08 18
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
include <iostrem.h>
int main ()
{
 char s1[16]="qwer";
 char *s2;
 char *s3;
 char *s4;
 int i;
 s2=s1; // Допустимо, присваивается адрес нулевого элемента.
 s3=new char [16];
 for (i=15; i>=0; --i)
 {
  s3[i]=s1[i]; // Допустимо, s3[i] - i-тый элемент динамического массива, на начало которого указывает s3.
 }
 s4=new char [16];
 for (i=15; i>=0; --i)
 {
  *(s3+i)=*(s1+i); // Не проверял, но вроде бы допустимо, (s1+i) - i-тый элемент "динамического" массива, на начало которого указывает s1.
 }
 std::cout<<s1<<std::endl; // Выводит qwer
 std::cout<<s2<<std::endl; // Выводит qwer
 std::cout<<s3<<std::endl; // Выводит qwer
 std::cout<<s4<<std::endl; // Не проверял, но должно быть выведено qwer
 delete [] s3;
 delete [] s4;
 return 0;
}
Вообще, массив и указатель на его нулевой элемент - одно и тоже, на сколько мне известно, иначе "думает" только sizeof: в примере sizeof (s1) равен 16, то есть размеру самого массива, а sizeof (s2), sizeof (s3) и sizeof (s4) равны размеру указателя.

Добавлено через 1 минуту
Цитата Сообщение от Duss Посмотреть сообщение
отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию
и
инициализация: невозможно преобразовать 'char *' в 'int *'
Исходник в студию.

Добавлено через 3 минуты
Цитата Сообщение от Duss Посмотреть сообщение
а в out_data указатель на res отправить.
C++
1
ut_data = *(unsigned char **)&res;
Нельзя: значение ut_data есть адрес простого указателя на char, оно не может быть передано вызывающей программе, надо в память по этому адресу записать другой адрес - значение простого указателя на char, оно же адрес нуль-терминальной строки.

Добавлено через 1 минуту
Запомни: сам параметр может быть возвращён вызывающей программе только в том случае, если он ссылка. Если же это указатель, то вернуть информацию можно только через память по адресу, равному полученному значению параметра.

Добавлено через 2 минуты
Цитата Сообщение от Duss Посмотреть сообщение
К вызывающей программе есть мануал, в нем сказано, что она вызывает функцию
MtSrvManagerProtocol
Синтаксис описан в .h файле
Да. Но она уже с ним скомпилена. И в ней уже не учтены те переменные, которые ты придумал после её компиляции. Синтаксис вызова учтён, а глобальных переменных библиотеки она не знает, так как они не учтены и не могли быть учтены при написании самой программы. Твоя библиотека - другая программа и о ней вызывающая не знает ничего, кроме синтаксиса вызова использованных в вызывающей программе функций из твоей библиотеки.
1
17.11.2012, 22:08
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.11.2012, 22:08
Помогаю со студенческими работами здесь

Указатели на указатели с числами. Почему можно присвоить число в 4-ый элемент, если массив из 2 элементов?
Есть массив int **mas; mas=new int*; // выделил место под пять строк, верно ? mas=new int;//...

Отсортировать массив и вывести на экран (массивы и указатели на указатели)
Даны массивы F-фамилий студентов и S-результаты сессии (5 оценок) , причем s- результат сессии F...

Указатели на указатели: для чего они могут понадобятся?
Изучаю C++, дошёл до указателей на указатели. Там пишут что эта тема не обязательна. Для чего они...

Указатели на указатели, как правильно разыменовать, где ошибка?
1)Есть класс: Shape - абстрактный; у него есть классы наследники: Circle, Triangle. 2)Eсть...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru