Добрый день, друзья.
Выдалась свободная минутка, решил написать небольшой пост, по мотивам уже заданных мне ранее вопросов. Быть может кому-то эти советы, тоже будут полезны. Итак, сегодня займемся циклами.
Рассмотрим цикл for().
Как вы уже знаете, синтаксис  этой конструкции имеет следующий вид:

for(инициализация счетчика; условие; изменение счетчика)
    оператор

Кроме того, мы помним, что после цикла всегда стоит один оператор, но если нам необходимо в теле цикла выполнить несколько действий, то мы можем использовать составной оператор {}. Все что заключено в фигурные скобки, будет считаться за один единственный оператор.
Если вы еще не забыли, а это не мудрено с моей-то частотой выпуска занятий, то последнем уроке мы изучали двойные массивы. Одной из типичных задач является вывод массива размерности [N][M] на экран в виде таблицы (или матрицы) в N-строк и M столбцов. Для этой задачи очень крайне удобно использовать два вложенных цикла for. Например:
Листинг 1.

#include <stdio.h>
#include <stdlib.h>
#define N 10
#define M 8

int main(void){
    int arr[N][M];
   
    for (int i=0;i<N;i++)
        for (int j=0; j<M; j++)
            arr[i][j]=rand();
   
    for (int i=0;i<N;i++)
        for (int j=0; j<M; j++)
            printf(«%d\t»,arr[i][j]);
   
return (0);
}

Но если мы оставим этот код таким, то массив будет выводиться не табличкой, а строчкой. Нужно добавить еще переход на новую строку, после того, как мы закончили выводить все элементы текущей. Ну т.е. после каждого внутреннего цикла for нужно перенести строку. Исправим.
Листинг 2.

#include <stdio.h>
#include <stdlib.h>
#define N 10
#define M 8

int main(void){
    int arr[N][M];
   
    for (int i=0;i<N;i++)
        for (int j=0; j<M; j++)
            arr[i][j]=rand();
   
    for (int i=0;i<N;i++){
        for (int j=0; j<M; j++)
            printf(«%d\t»,arr[i][j]);
        printf(«\n»);
    }
return (0);
}

Вот так уже лучше. Так, наша программа будет выводить все так, как нужно. Вот, посмотрите на следующую картинку.

Рис.1. Результат работы программы.

А теперь поговорим о красоте. Этот вот дополнительный перенос строки , он как шило в заднице. Из-за него одного пришлось добавить составной оператор. Некрасиво получилось. Есть ли способ этого избежать. Да, есть!
Я вам раньше не говорил, а теперь скажу. В заголовке цикла for на месте инициализации счетчика и на месте изменения счетчика, могут стоять не одна, а сразу несколько инструкций. Чтобы их туда записать нужно использовать еще один оператор, оператор последовательного выполнения – ,.  Да-да, просто запятая. 
Как это может помочь нам. Да вот как. Смотрите, мы добавляем перенос, на каждой новой итерации внешнего цикла, вот и добавим наш printf в блок изменение счетчика.
Листинг 3.

#include <stdio.h>
#include <stdlib.h>
#define N 10
#define M 8

int main(void){
    int arr[N][M];
   
    for (int i=0;i<N;i++)
        for (int j=0; j<M; j++)
            arr[i][j]=rand();
   
    for (int i=0;i<N;i++,printf(«\n»))
        for (int j=0; j<M; j++)
            printf(«%d\t»,arr[i][j]);
       

return (0);
}

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

Рассмотрим один показательный пример. Используем для вывода двойного массива на экран  один цикл for. Это будет выглядеть например так:
Листинг 4:

#include <stdio.h>
#include <stdlib.h>
#define N 10
#define M 8

int main(void){
    int arr[N][M];
   
    for (int i=0;i<N;i++)
        for (int j=0; j<M; j++)
            arr[i][j]=rand();
   
    for (int i=0, j=0 ;i<N; j++){
        printf(«%d\t»,arr[i][j]);
        if (M-j==1){
           printf(«\n»);
           i++;
           j=-1; 
        }
    }  

return (0);
}

А на мониторе снова никаких изменений. ))

Рис.2. Результат работы программы.

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

UPD(от 2.02.14): Я говорил же вам, что этот код может запутать любого. Я и сам попался в эту ловушку. Записанный ранее код, был ошибочен. Стараниями внимательного читателя он исправлен, и теперь работает так, как ему и подобает. =))

Я не помню, рассказывал я о именованных константах, которые использую в своих примерах в этом уроке. На всякий случай расскажу еще раз.
Для объявления именованных констант служит директива #define. Её синтаксис таков

#define имя значение

Важно! Не нужно ставить в конце точку с запятой. А так же между именем и значением знак присвоения =.

Как работает эта инструкция, рассмотрим на нашем примере. Перед тем как компилятор начнет обрабатывать программу, он пройдется по всему коду и заменит все места, где встречается N или M и вместо них подставит в код их значения: 10 и 8 соответственно.  Причем компилятору вообще по барабану, что на что мы заменяем. С учетом этой особенности, некоторые используют при написании код «Боярский язык». Ну т.е. пишут код на обычном русском языке.  Например вот так.
Листинг 5.

#include <stdio.h>
#include <stdlib.h>

#define N 10
#define M 8
#define целое int
#define присвоить =


целое main(void){
    целое arr[N][M];
   
    for (целое i присвоить 0;i<N;i++)
        for (целое j присвоить 0; j<M; j++)
            arr[i][j] присвоить rand();
   
    for (целое i присвоить 0, j присвоить 0 ;i<M,j<N;i++){
        printf(«%d\t»,arr[i][j]);
        if (M-i==1){
           printf(«\n»);
           j++;
           i присвоить 0; 
        }
    }
return (0);
}

И если вы думаете, что такой код не будет работать, то вы ошибаетесь.  Хотя, конечно это все для забавы, и писать что-то серьезное так не следует. Но кому стало интересно — погуглите и найдете что-нибудь интересное для себя.

На сегодня всё. Удачи вам и красивого кода. ))

От KaDeaT