Как приблизиться к указателям в C? [дубликат]

  1. Сделайте toggle глобальной переменной,
  2. Для производительности сделайте img глобальной,
  3. Установите переход на элемент только один раз .

Таким образом:

function foo() {
  if (img.style.width == "") {
    img.style.width = "0px";
  }

  let width = parseInt(img.style.width.match(/\d+/g)[0]);

  if (toggle) {
    width -= 50;
  }
  else {
    width += 50;
  }

  img.style.width = width + "px";

  toggle = !toggle;

}

const img = document.querySelector('.product-image');
let toggle = true;

img.style.transition = "all 2s";

let interval = setInterval(foo, 1000);
7
задан Lundin 4 September 2017 в 08:58
поделиться

13 ответов

Печать адресов и значений является разумным способом посмотреть на них. Но если можно разбудить отладчик и выполнение, это намного лучше, потому что можно следовать за указателями быстрее, наблюдайте, что они изменяются, когда Вы ступаете и так далее.

Если Вы знакомы с "ярлыками" в Windows или гибкими ссылками в файловых системах Linux, то он мог бы помочь, так же, как Вы начинаете, для размышления об указателе как о ярлыке (softlink) к другому объекту (является ли тот объект структурой, встроенным типом, другим указателем, и т.д.).

Ярлык является все еще файлом. Это занимает свое собственное место на дисководе, это относится к другому файлу, и это может быть изменено для обращения к другому файлу файла от того, для чего это привыкло. Точно так же указатель в C является объектом, который занимает память, содержит адрес другой ячейки памяти и может быть изменен для содержания другого адреса только путем присвоения ему.

Одно различие - то, если Вы дважды щелкаете по ярлыку, оно ведет себя, как будто Вы дважды щелкнули по вещи, на которую оно указывает. Это не имеет место с указателями - всегда необходимо явно разыменовывать указатель с "*" или "->" для доступа к вещи, на которую он указывает. Другое различие - то, что довольно распространено иметь указатели на указатели на что-то в C.

Что касается жаргона, просто необходимо изучить это, к сожалению. "интервал doSomething (символ ** hihi)" означает "функцию, вызванную doSomething, который возвращает целое число и берет в качестве параметра указатель на указатель символ". Критический момент - это"char ** hihi"означает "pointer-to-pointer-to-char. Мы назовем pointer-to-pointer-to-char hihi". Вы говорите, что "тип" hihi является символом **, и что "тип" *hihi (что Вы получаете при разыменовании указателя) является символом*, и тип ** hihi является символом.

Часто в C, указатель на символ означает строку (другими словами, это - указатель на первый символ в NUL-завершенном массиве). Так часто "символ *" означает "строку", но это не имеет к. Это могло бы просто означать указатель на один символ. Немного как ярлык на 1-байтовый файл в Windows (хорошо, с FAT32 так или иначе), указатель на символ в C на самом деле больше, чем вещь, на которую он указывает :-)

Аналогично, символ ** часто означает не только указатель на один указатель строки, но и на массив указателей строк. Это не могло бы, но если это делает затем следующее небольшое изображение, мог бы помочь:

hihi
 ____            ____                     ________     _________      _______
|____|   -----> |____|  *hihi       ---> |___A____|   |___B_____|    |___C___|
                |____|  *(hihi+1)   ------------------^              ^
                |____|  *(hihi+2)   ---------------------------------|
                | ...|    etc.

hihi указывает на усилие многоквартирного дома, которое является моим способом представить массив указателей. Как Вы уже отметили, я, возможно, записал hihi [0] вместо *hihi, hihi[1] вместо * (hihi+1), и так далее.

Это - непрерывный блок памяти, и каждый блок размера указателя ее содержит адрес (то есть, она "указывает на"), другой блок памяти, от goodness-knows-where, содержа один или несколько символов. Так, hihi [0] адрес первого символа строки A, hihi[1] является адресом первого символа строки B.

Если hihi не указывает на массив, просто единственный указатель, то многоквартирный дом является бунгало. Аналогично, если *hihi не указывает на строку, всего один символ, то длинный тонкий блок является квадратом. Вы могли бы спросить, "как я знаю, сколько этажей многоквартирный дом имеет?". Это - грандиозное предприятие в C, программирующем - обычно или функциональная документация сказала бы Вам (это могло бы сказать "1", или "12", или "достаточно для вещи Вы говорите мне делать", или иначе Вы передали бы количество этажей как дополнительный параметр, или иначе документация скажет Вам, что массивом является "ПУСТОЙ УКАЗАТЕЛЬ, завершенный", означая, что это будет продолжать читать, пока это не будет видеть ПУСТОЙ УКАЗАТЕЛЬ адреса/значения, и затем остановитесь. Основная функция на самом деле делает и вторую и третью вещь - argc, содержит количество аргументов, и только быть на безопасной стороне argv ЗАВЕРШАЕТСЯ ПУСТЫМ УКАЗАТЕЛЕМ.

Так, каждый раз, когда Вы видите параметр указателя, необходимо посмотреть на документацию для функции, чтобы видеть, ли это, ожидая указатель на массив, и раз так насколько большой массив должен быть. Если Вы не будете осторожны относительно этого, то Вы создадите своего рода ошибку, названную "переполнением буфера", где функция ожидает указатель на большой массив, Вы даете ему подсказку к небольшому массиву, и это набрасывает от конца того, что Вы дали ему и начинаете повреждать память.

9
ответ дан 6 December 2019 в 15:32
поделиться

Я думаю, что это - то, где классические книги более полезны, чем ресурсы самые онлайн. Если можно получить копию, считайте Язык программирования C (иначе K&R) очень очень тщательно. Если Вы хотите знать больше, пойдите для Опытного Программирования C: Непостижимые тайны (просто гуглят его).

6
ответ дан 6 December 2019 в 15:32
поделиться

В то время как чтение K&R могло бы быть лучшим выбором здесь, я попытаюсь сделать это немного более ясным:

Сам указатель является переменной. Но вместо того, чтобы хранить значение это только хранит адрес. Думайте о нем как индекс: как в Вашей адресной книге индекс для чего-то Вы ищете (скажите, номер телефона к некоторому имени), это указывает туда, где информация хранится. В Вашей адресной книге это могло бы сказать, "смотрят на страницу 23 для нахождения номера телефона Joe". В случае указателя это просто говорит, "смотрят на адрес памяти 1234 для получения информации, на которую я указываю". Поскольку само значение указателя является только адресом памяти, можно сделать арифметику с ним - как добавление значений (который совпал бы с элементами доступа массива: если указатель укажет на массив, то адрес после того, на который указывает указатель, получит доступ к следующему элементу в массиве). Ваша функция в качестве примера int doSomething(char *hihi) будет иметь hihi, указывающий на адрес памяти, который Вы передали его при вызове его. Это полезно, если Вы хотите передать большие объемы данных - вместо того, чтобы копировать данные (который происходит в функции как void blah(int a) со значением a) Вы только копируете его местоположение.

Я не учел некоторые детали в вышеупомянутом, но я надеюсь, что оно дает Вам по крайней мере некоторое основное понимание. Я настоятельно рекомендую читать K&R или подобную книгу по теме.

0
ответ дан 6 December 2019 в 15:32
поделиться

Указатель является местом.

Массив является последовательной группой мест.

Всегда существует значение в месте. (Это может быть оставшийся спам).

Каждая переменная имеет место.

Для переменных указателя значение в его месте является местом.

Это похоже на поиск сокровищ. "Посмотрите в почтовом ящике 13 для примечания, которое говорит Вам, какой почтовый ящик содержит Вашу поздравительную открытку".

И если почтовый ящик 13 будет содержать примечание, которое читает "13", то Ваша поздравительная открытка будет долгим временем, появляясь! (Это - ошибка, вызванная круговой ссылкой указателя.;-)

2
ответ дан 6 December 2019 в 15:32
поделиться
/* Given a string of characters like this one: */
char *string = "Hello!\n";

/* Memory will contain something like:
0x00100 'H'
0x00101 'e'
0x00102 'l'
0x00103 'l'
0x00104 'o'
0x00105 '!'
0x00106 '\n'
0x00107 '\0'
*/

/* And the program code will say: */
string=0x00100;

/* C doesn't really have arrays */
char c=string[3];
/* is just syntactic sugar for: */

char c=*((char*)((void*)string + 3 * sizeof(char)));
/* ie. 0x00100 + 3 * 1 */
/* ie. 0x00103 */
/* and * dereferences 0x00103, this means char_in(0x00103) */

/* When you pass a pointer you are actually passing the value
   of the memory position */

int a;          /* allocates space for a random four byte value in
                   0x00108 */
scanf("%d",&a); /* &a = 0x00108 scanf now knows that it has to store
                  the value in 0x0108 */

/* Even if you declare: */
int b[23];
/* b will be just a pointer to the beginning of 23 allocated ints.
   ie. 0x0010C */

/* pointer arithmetic is different from normal types in that: */
b++;
/* is actually: */
b+=4; /* b+=1*sizeof(int); */
/* So pointers in C work more like arrays */
0
ответ дан 6 December 2019 в 15:32
поделиться

Давос, Вы в колледже? Действительно ли Вы - главная Информатика? Одна вещь, которую Вы могли бы рассмотреть, посещает урок ассемблера (MIPS, x86). Я был главной Электротехникой, и я был обязан посещать подобные низкоуровневые уроки. Одна вещь, которую я наблюдал, состояла в том, что наличие ясного понимания ассемблера действительно помогло мне, когда я был запущен, изучив C++. В частности, это дало мне намного более ясное понимание указателей.

Указатели и разыменование являются фундаментальными понятиями на уровне ассемблера. Если Вы изучаете указатели впервые, я нахожу, что до некоторой степени "C" скрывает его немного слишком много, и это на самом деле становится более ясным на уровне ассемблера. Затем можно взять то более низкое знание уровня и видеть, как "C" язык просто помещает некоторый синтаксис сверху его.

Просто мысль. Кроме этого, K&R является замечательной книгой, как несколько человек упомянули и также, реализование некоторых абстрактных типов данных как связанные списки может быть полезным, особенно при рисовании схем, показывающих расположение памяти это может помочь разъяснить идею.

0
ответ дан 6 December 2019 в 15:32
поделиться

По моему скромному мнению, лучший способ "получить" указатели состоит в том, чтобы сделать некоторое программирование ассемблера. После того как Вы привыкли думать с точки зрения необработанного содержания регистра (без реального различия между данными и адресами кроме от того, как Вы используете их), и инструкции по загрузке и хранению, типы указателей C будут иметь намного больше смысла (и Ваша оценка того, что C делает для Вас, будет значительно улучшен).

0
ответ дан 6 December 2019 в 15:32
поделиться

Если Вы действительно хотите понять указатели, Вам нужна хорошая лекция колледжа.

Лучший, который я когда-либо видел, является этим.

Ничто иное не выдерживает сравнение.

Также проверьте лекцию по Turing. Это очень хорошо сделано.

0
ответ дан 6 December 2019 в 15:32
поделиться

Много хороших ответов, данных выше. Некоторое другое понимание - то, что указатель всегда является типом беззнаковых целых чисел. Объект или переменная, на которую это указывает в памяти, могут иметь любой тип.

В 32-разрядной операционной системе целое число является 4-байтовым числом и должно быть в диапазоне

0 <значение указателя <(2^^32)-1

В 64-разрядной операционной системе целое число является 8-байтовым числом и должно быть в диапазоне

0 <значение указателя <(2^^64)-1

Значение указателя = 0 интерпретируется как специальное флаговое значение под названием ПУСТОЙ УКАЗАТЕЛЬ, который указывает, что этот указатель не указывает на применимую переменную.

Указатели используются для косвенности. Некоторые регистры в ЦП действуют как указатели, например, счетчик команд (PC) и адресные регистры.

0
ответ дан 6 December 2019 в 15:32
поделиться

Это кажется, что Вы покрыли основы. Я не перешел бы к шпаргалкам, пока Вы не пошли далее по некоторой литературе. Причина быть осторожным, когда работа с указателями состоит в том, что они позволяют Вам непосредственно получать доступ к определенным адресам памяти и если Ваш код делает тот неправильные вещи, повредится. Массив укажет на первое местоположение и в зависимости от типа массива, можно получить доступ к дальнейшим местоположениям в массиве путем работы с указателем того же типа хранимой суммы массива.

Я сначала понял бы переменные, lvalue, rvalue и присвоения, затем указатели как типы переменных, затем разыменование указателя и дальнейшие операции указателя. Потребовалось бы вполне немного для разработки это и уже существует много хороших доступных ссылок.

Можно найти вводное учебное руководство здесь (действительно подробное объяснение). PDF Прямая ссылка.

0
ответ дан 6 December 2019 в 15:32
поделиться

Вы считали K&R? Если бы Вы не имеете, я сказал бы, что это - то, где необходимо запустить.

-1
ответ дан 6 December 2019 в 15:32
поделиться

Несколько нетрадиционное предложение: http://www.youtube.com/watch?v=Rxvv9krECNw

Это - лекция от Более высоких Вычислений 1 в моем uni с прошлого года. Первые несколько минут будут немного бесполезны (подвергните администраторский материал типа), но иначе это - действительно хорошее объяснение

-1
ответ дан 6 December 2019 в 15:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: