программисты!Адреса указателей и арифметических указателей
Я полностью погружен с двойной стрелкой (указатель на указатели) ... Много вопросов здесь!
Начнем с выполнения этой задачи: Я пишу свою собственную версию функции calloc func, которая должна возвращать указатель на 'n' элементы памяти размера 'size'. Вот что я придумал:
void **calloc1(int n, int size)
{
int i, j;
char *tmp, **p = NULL;
tmp = (char *) malloc1(n * size);
p = tmp;
for (i = 0; i < n; i++) {
p[i] = tmp;
for (j = 0; j < size; j++)
tmp++;
}
p = &p[0];
return (void **)p;
}
/* I entered n==4, size==3; real pointers are: p[0] == 0x804cfe0; p[1] == 0x804cfe3; p[2] == 0x804cfe6; ... */
Таким образом, по существу, я выделяю п * байт размера, а затем «назначить» массив указателей равного размера «» на соответствующие стартовые позиции. Введем n = 4 и size = 3; это означает, что p [0] указывает на tmp [0], p [1] на tmp [3], p [2] на tmp [6] и т. д. В GDB я отслеживаю значения указателей почти после каждого шага.
Тогда в «основной» Я объявляю двойной указатель и «прикрепить» его буфер получил от моего «calloc»:
int main (short argc, char **argv)
{
char **space;
space = (char **) calloc1(n, size); /* removing '(char**)' here does not have effect */
/* at this stage pointers seems to be correctly "located": 'space' == 'space[0]' == 0x804cfe0; 'space[1]' == 0x804cfe3; 'space[2]' == 0x804cfe6; ... */
1) Вот уже первый вопрос: как может «главный () '(или любая другая функция, через которую я передам копию ** p), будет знать размер арифметики указателя? Например, как «main()» знает, что если я добавлю «1» в «пробел» (или просто увеличиваю его один раз), он должен указывать на свой второй указатель (в «calloc» это p [1]), который (в этом конкретном случае) является еще 3 символами первого указателя (p [0])? Кроме того, если я создаю в массиве «alloc» указателей на строки с «переменной длиной» (например, p [0] указывает на tmp [0], p [1] на tmp [7], p [2] на tmp [11] и т. д.), как любая другая функция знает, где она должна увеличивать «верхний» указатель на 4 и где на 7 «символов»?
Хорошо, мы двигаемся дальше, я пытаюсь поставить некоторые символы в приобретаемой буфер:
int i = 0, j = 0, n, size;
char nn, ssize, c, temp[3];
printf ("Enter number/size \n");
sc = scanf ("%c/%c", &nn, &ssize);
n = nn - '0'; /* n==4 */
size = ssize - '0'; /* size==3 */
printf ("Enter a 'number' of words\n");
while (j < n) {
for (i = 0; (c = getchar()) != EOF && i < size; i++)
*(*space)++ = c;
(*space)--; /* this line is unneccesary; if I remove it - nothing changes */
++j;
++space;
}
2) А вот свидетельство на первый вопрос: на самом деле, когда я увеличиваем «пространство» здесь, она движется не на 3, а на 4 символа (после первого «++» это 0x804cfe4, после второго 0x804cfe8). Зачем? Есть ли связь с размером «float»? После первого такого приращения «* space» указывает на 0x804cfe6 ... Я не думаю, что это правильно.
Я попробовал другой путь - ссылается на «пространство», как не указатель, а массив:
....
while (j < n) {
for (i = 0; (c = getchar()) != EOF && i < size; i++)
*space[j]++ = c;
space[j]--;
++j;
}
3) В этом случае, указатели, кажется, все в порядке - например, space [1] == 0x804cfe3, space [2] == 0x804cfe6. Проблема в том, что, хотя этот цикл работает с j == 2, значение 'space [0]' как-то изменяется от 0x804cfe2 (перемещается дважды - ok) на что-то вроде 0x6a04cfe2 (что выходит за рамки). Что за ..
4) И вообще, существует какое-то странное поведение адресов. Кроме того, я старался не писать символы непосредственно ** пространства, но использовать функцию копирования строки:
char i, temp[3];
...
while (j < n) {
for (i = 0; (c = getchar()) != EOF && i < size; i++)
temp[i] = c;
strncpy1 (space[j],temp,3);
++j;
}
.....
void strncpy1 (char *s, char *t, int k)
{
while (--k > 0) {
*s = *t;
s++; t++;
}
}
Внутри копирования FUNC, копирование и увеличивающиеся шоу в GDB правильный. Но после возвращения из 'strncpy1', пространство [j] изменяется от 0x804cfe0 до примерно 0x804000a. Как возможно, что вызываемая функция может влиять на указатель родителей (внешний)?
Итак, какой тип указателя-указателя-символа? Какой у него размер?
Я не понимаю, что вы пытаетесь сделать с вашей функцией calloc. Почему он возвращает 'void **' вместо того, чтобы возвращать' void * ', как это делает обычный calloc? – hugomg
Да, я ожидал такого вопроса)) в любом случае, меняя calloc1 с 'void **' на 'void *' (и возвращая тип указателя from '(void **) p' to '(void *) p') не имеет никакого эффекта ... – digitest
Прежде чем делать что-либо еще, нарисуйте карту памяти на бумаге, где расположены ваши распределения памяти, и где указывается каждый указатель. –