Я застрял в следующем цикле while. Обновлено: Цель программы — полностью перебрать массив от начала до конца, как указано в заголовке. Для этого я попытался использовать цикл while
while(*rtn)
считается ложным, пока первое значение равно нулю (см. пример 0 ниже), поэтому программа не входит в цикл while. Если я изменю первое значение на ненулевое (пример 1), программа войдет в цикл while. Если я изменю присвоение значения так, чтобы пятый элемент был равен нулю (пример 2), цикл while остановится на пятом элементе. Цикл for работает как положено.
size_t sz = 100 ;
int *rtn = malloc(sz*sizeof(int));
int cnt ;
for(cnt = 0 ; cnt < sz ; cnt++){
EXAMPLE 0 rtn[cnt] = cnt*2 ; // First value of array is 0
EXAMPLE 1 rtn[cnt] = cnt*2 + 5 ; // first value of array is non zero
EXAMPLE 2 rtn[cnt] = 5 - cnt ; // fifth value will be 0
}
cnt=0 ;
printf("\n---WHILE LOOP---\n") ;
while(*rtn){
printf("%3d - %4d\n",cnt, *rtn) ;
cnt++ ;
rtn++ ;
}
printf("\n---FOR LOOP---\n") ;
for(cnt = 0 ; cnt < 10 ; cnt ++){
printf("%3d - %4d\n", cnt, rtn[cnt]) ;
}
Я думал, что цикл while проверяет NULL-указатель, а не 0, который, очевидно, может быть допустимым значением!? Также, если я изменю цикл while на
while(rtn){
...
}
он просто пройдет всю память (?) и завершится ошибкой. Итак, по сути, цикл while не является подходящим инструментом для перебора массива int?!
В C нулевое целое число считается ложным, поэтому цикл завершится, как только встретится первый ноль в массиве.
Почему бы тогда не проверить цикл while, если указатель равен нулю? Если только прямое сравнение с NULL не рекомендуется в C.
Имейте в виду, что while(*rtn)
эквивалентно while (rtn[0] != 0)
. И что если в массиве нет 0
, ваш цикл выйдет за пределы, и у вас будет неопределенное поведение.
@FrasherGray Технически, если rtn
изначально не является нулевым указателем, он никогда не станет нулевым указателем. Если только код явно не выполняет назначение rnt = NULL
.
@sake Что еще хуже, когда вы доберетесь до цикла for
, у вас больше не будет исходного значения rtn
. Он теряется в цикле while
. Так что там вы пойдете еще дальше за пределы поля.
Ох, да это мб. Насколько я понимаю, ему просто нужен способ проверить, находится ли указатель в выделенной памяти?
Что касается решения проблемы, цикл for
типа for (a; b; c) { d; }
эквивалентен { a; while (b) { d; c; } }
. Так что вы все еще можете использовать такой цикл while
. Или отслеживать конец выделенной памяти, например int *end = rtn + cnt;
, а затем while (rtn < end)
Пожалуйста, проясните вопрос и предоставьте воспроизводимый код. Что вы на самом деле пытаетесь сделать? Какой (воспроизводимый) код вы используете и ведет себя не так, как вы ожидаете? Чего ты ожидал?
Непонятно, что вы спрашиваете в своем вопросе, но нет ничего плохого в использовании циклов while
или циклов for
для любой из упомянутых вами задач. Ниже приведены примеры использования любого из них для перебора каждого элемента. Также есть примеры использования любого из них для итерации до тех пор, пока не будет найден «ложный» элемент (может выйти за пределы, если нет «ложного» элемента). Также есть пример цикла while
, который выполняет то же самое с синтаксисом из вашего вопроса.
#include <stdio.h>
#include <stdlib.h>
int main() {
int sz = 5; // I made this smaller for my example
int* rtn = malloc(sz * sizeof(int));
int cnt;
// Populate some random data
rtn[0] = 3;
rtn[1] = 2;
rtn[2] = 0;
rtn[3] = 1;
rtn[4] = 4;
// If your goal is to iterate over every element this works
printf("For every element\n");
for (cnt = 0; cnt < sz; cnt++) {
printf("%d\n", rtn[cnt]);
}
// If your goal is to iterate over every element this works too
printf("While every element\n");
cnt = 0;
while (cnt < sz) {
printf("%d\n", rtn[cnt]);
cnt++;
}
// If your goal is to iterate until you find a "false" element this does
// that BUT it will go out of bounds if there is no "false" element
printf("For until \"false\" element\n");
for (cnt = 0; rtn[cnt]; cnt++) {
printf("%d\n", rtn[cnt]);
}
// If your goal is to iterate until you find a "false" element this does
// that too. It also will go out of bounds if there is no "false" element
printf("While until \"false\" element\n");
cnt = 0;
while (rtn[cnt]) {
printf("%d\n", rtn[cnt]);
cnt++;
}
// Yet another way to do the exact same as the previous while loop
printf("Another while until \"false\" element\n");
while (*rtn) {
printf("%d\n", *rtn);
rtn++;
}
return 0;
}
спасибо, искал решение с циклом while, чтобы лучше понять арифмерику указателей
Ваше понимание поведения цикла while (*rtn)
в C правильное. Условие цикла while (*rtn)
оценивает значение, на которое указывает rtn
. Если значение равно нулю, оно считается false
и цикл завершается. Вот почему в ваших примерах:
Цикл while (*rtn)
действительно проверяет значение, на которое указывает rtn
, а не NULL-указатель.
Условие while (*rtn)
не подходит для перебора массива, если любой элемент массива может быть равен нулю. Он останавливается, как только встречает первый ноль, который может не быть концом массива.
Чтобы перебрать весь массив, вы можете использовать цикл for
или цикл while
с явным счетчиком. Вот как это можно сделать с помощью цикла for
:
#include <stdio.h>
#include <stdlib.h>
int main() {
size_t sz = 100;
int *rtn = malloc(sz * sizeof(int));
int cnt;
// Example 0: First value of array is 0
for (cnt = 0; cnt < sz; cnt++) {
rtn[cnt] = cnt * 2;
}
// Example 1: First value of array is non-zero
for (cnt = 0; cnt < sz; cnt++) {
rtn[cnt] = cnt * 2 + 5;
}
// Example 2: Fifth value will be 0
for (cnt = 0; cnt < sz; cnt++) {
rtn[cnt] = 5 - cnt;
}
printf("\n---WHILE LOOP---\n");
cnt = 0;
while (cnt < sz) {
printf("%3d - %4d\n", cnt, rtn[cnt]);
cnt++;
}
printf("\n---FOR LOOP---\n");
for (cnt = 0; cnt < 10; cnt++) {
printf("%3d - %4d\n", cnt, rtn[cnt]);
}
free(rtn);
return 0;
}
Объяснение:
rtn
.while
с явным счетчиком для перебора всего массива.for
для печати первых 10 элементов массива.Используя счетчик в цикле while
(while (cnt < sz)
), вы гарантируете, что выполните итерацию по всему массиву, независимо от содержащихся в нем значений.
В дополнение к другим ответам - вы можете остановить цикл, создав указатель на конец массива, а затем проверив цикл, когда он достигнет конца, например:
size_t sz = 100;
int *rtn = malloc(sz*sizeof(int));
int *end = rtn + sz;
...
printf("\n---WHILE LOOP---\n");
while (rtn < end) {
...
++rtn;
}
Кстати, вы создаете утечку памяти, изменяя указатель, который возвращает malloc()
. Вам нужно free()
массив, когда вы закончите его использовать. Поэтому вам следует использовать другой указатель для перебора массива, например:
int *arr = malloc(...);
...
printf("\n---WHILE LOOP---\n");
int *rtn = arr;
while (...) {
...
++rtn;
}
...
free(arr);
rtn < end — это именно то, что я искал, спасибо!
Ваш вопрос действительно не имеет смысла. Вы заинтересованы в переборе каждого элемента массива или в переборе до тех пор, пока не увидите «ложное» значение (включая
0
илиNULL
)? Имеет смысл сделать и то, и другое. Если вы хотите перебрать каждый элемент, либо используйте цикл for, либо создайте цикл while, который проверяет, достиг лиcnt
конца.