
Создание нового массива из отрицательных элементов исходного:
#include <stdio.h>
main()
{
int i; // временные переменные
int array[10]; // это сам массив
int size = 10; // это размер массива (от 0)
int nw_array[10]; // это будущий массив.
int nw_size = 0; // его размер пока не известен. обнуляем.
// -------------------------------------
// ввод элементов:
// -------------------------------------
for( i=0; i<size; i++ )
{
printf( "\n array[%d]: ", i );
scanf( "%d", &array[i] );
}
// -------------------------------------
// Создаем массив из отриц. эл-тов
// -------------------------------------
for( i=0; i<size; i++ )
if( array[i] < 0 )
{
nw_array[nw_size] = array[i];
nw_size++;
}
// -------------------------------------
// На экран его!
// -------------------------------------
if( nw_size )
puts( "array have no elements below zero" );
else // К.О. кстати, это не обязательно, т.к. цикл тогда просто не выполнится.
{
for( i=0; i<nw_size; i++ )
printf( "\n %d", nw_array[i] );
}
getch();
return 0;
}
19. Сортировка элементов одномерного массива.
#include <stdio.h>
main()
{
int i,j,t; // временные переменные
int forsort[10]; // это сам массив
int size=10; // это размер массива
// -------------------------------------
// ввод элементов:
// -------------------------------------
for( i=0; i<size; i++ )
{
printf( "n forsort[%d]: ", i );
scanf( "%d", &forsort[i] );
}
// -------------------------------------
// сортировка:
// -------------------------------------
for( i=0; i<size-1; i++ )
{
for( j=i+1; j<size; j++ )
{
if( forsort[i] > forsort[j] )
{
t = forsort[i];
forsort[i] = forsort[j];
forsort[j] = t;
}
}
}
// -------------------------------------
// выводим сие чудо:
// -------------------------------------
for( i=0; i<size; i++ )
printf( "n%d", forsort[i] );
getch(); // чтоб успеть все это прочитать ^^^
return 0; /* а это потому что мейн целый ( main() <=> int main() ) и
он по-хорошему должен что-то возвращать целое. например,
ноль. а можно написать void main() и ничего не возвращать.
*/
}
20. Указатели.
Указатель - это переменная, содержащая адрес другой пе-
ременной. указатели очень широко используются в языке "C".
Это происходит отчасти потому, что иногда они дают единст-
венную возможность выразить нужное действие, а отчасти пото-
му, что они обычно ведут к более компактным и эффективным
программам, чем те, которые могут быть получены другими спо-
собами.
Описание указателя переменной:
признаками переменной-указателя являются две составляющие:
1. тип объекта данных, для доступа к которому используется указатель.
2. * перед именем переменной.
Алсо, указатели часто используют при динамическом выделении памяти. Для того чтобы воспользоваться функциями динамической работы с памятью нужно включить заголовочный файл ALLOC.H:
#include <alloc.h>
а вот пример динамического выделения памяти:
int *p1;
p1 = (int*)malloc( sizeof(int) );
21. Операции над указателями.
присваивание
операция сравнения, сложения, вычитания.
Можно сравнивать указатели одинакового типа. Важной особенностью арифметических операций с указателями является то, что физическое увеличение или уменьшение значения указателя зависит от его типа.
22-23)Связь одномерных-двумерного массивов с указателями.
Между указателями и массивами существует определенная связь. Предположим, имеется массив из 100 целых чисел. Запишем двумя способами программу суммирования элементов этого массива:
long array[100];
long sum = 0;
for (int i = 0; i < 100; i++)
sum += array[i];
То же самое можно сделать с помощью указателей:
long array[100];
long sum = 0;
for (long* ptr = &array[0];
ptr < &array[99] + 1; ptr++)
sum += *ptr;
Элементы массива расположены в памяти последовательно, и увеличение указателя на единицу означает смещение к следующему элементу массива. Упоминание имени массива без индексов преобразуется в адрес его первого элемента:
for (long* ptr = array;
ptr < &array[99] + 1; ptr++)
sum += *ptr;
Хотя смешивать указатели и массивы можно, мы бы не стали рекомендовать такой стиль, особенно начинающим программистам.
При использовании многомерных массивов указатели позволяют обращаться к срезам или подмассивам. Если мы объявим трехмерный массив exmpl:
long exmpl[5][6][7]
то выражение вида exmpl[1][1][2] – это целое число, exmpl[1][1] – вектор целых чисел (адрес первого элемента вектора, т.е. имеет тип *long), exmpl[1] – двухмерная матрица или указатель на вектор (тип (*long)[7]). Таким образом, задавая не все индексы массива, мы получаем указатели на массивы меньшей размерности.
24. Массивы указателей.
Так как указатели сами являются переменными, то вы впол-
не могли бы ожидать использования массива указателей. Это
действительно так.
Мы нуж-
даемся в таком представлении данных, которое бы позволяло
удобно и эффективно обрабатывать строки текста переменной
длины.
Здесь и возникают массивы указателей. Если подлежащие
сортировке сроки хранятся одна за другой в длинном символь-
ном массиве (управляемом, например, функцией ALLOC), то к
каждой строке можно обратиться с помощью указателя на ее
первый символ. Сами указатели можно хранить в массиве.
25. Строки символов.
Строка представляет собой одномерный массив значений типа char, завершающийся нулевым байтом. Символы строки располагаются в памяти друг за другом, причем крайний слева имеет младший адрес.
э т о с т р о к а \0
То, что идет после нулевого байта \0 можно не заполнять. При использовании строки функцией типа printf() текст после нуль-байта и сам нуль-байт выводиться не будут.
Строки обычно запоминаются одним из трех способов.
как литературные строки, введенные непосредственно в текст программы.
Например:
puts( "ололо" );
как переменные фиксированного размера, запоминаемые вместе с другими переменными, такими как целые или значения с плавающей запятой.
Например:
char str[] = "ололо";
Как указатели, которые адресуют строки, обычно запоминаемые в куче. (капитан очевидность: выделяется память под нужное количество символов включая пробелы, переводы каретки и т.д. плюс байт под нулевой байт. и указателю присваиваем адрес первого байта выделенной памяти ).
Например:
char *str = NULL;
str = malloc( 6*sizeof(char) ); // ололо = 5 букв по одному байту + 1 байт
strcpy(str, "ололо");
Для работы со строковыми функциями типа strcpy() нужно включить заголовочный файл STRING.H с помощью следующей строки:
#include <string.h>
важные функции, которые я бы отметил:
1) strlen( строка )
эта функция вернет длину строки в символах (без нулевого байта). таким образом, strlen("hello") вернет 5.
2) strcpy( destination, source )
Оператор присваивания для строк не определен. Если c1 и c2 - символьные массивы, вы не сможете скопировать один в другой так:
c1 = c2; // так нельзя
Чтобы скопировать одну строку в другую, вместо использования оператора присваивания вызовите функцию копирования строк strcpy().
strcpy(c1,c2); // четкий и верный годный вариант
Оператор копирует символы, адресуемые указателем c2, в память, адресуемую указателем c1, включая нулевые байты.
26. Использование указателей для адресации строк символов.
Указатели для для адресации строк символов используются, чтобы динамически выделить память под строку, в зависимости от её длины. При этом важно не забыть, что строка, в отличии от простого массива символов, имеет нуль-байт на конце, под который тоже нужно выделить байт, а, вернее, sizeof(char);
Ну вот придумал пример:
char *str = NULL; // если не установить адрес на нулл, то может не сработать
int i;
int j=10;
str = malloc( sizeof(char)*(j+1) ); // выделяем память под j символов и нулевой байт
for( i=0; i<j; i++ )
{
str[i] = getch(); // записываем поочередно все это в память
}
str[i] = '\0'; // и нуль-байт. теперь это строка.
puts( str ); // выводим на экран
27. Функции. Объявление и описание.
Принцип программирования основан на использовании функций. Выполенение прграммы начинается с выполнения главной функции - main().
Функция - самостоятельная единица программы, спроектированная для решения конкретной задачи, сущность которой формулируется простым предложением. (прим. а вот с этим я бы поспорил: ну-ка сформулируйте простым предложением функцию мейн из второй-третьей программы. так что нифига, это просто рекоммендация.)
Достоинства функции:
- позволяет избежать повторного программирования.
- одну и ту же функцию можно использовать в нескольких программах.
- использование функций облегчает чтение кода и внесение изменений.
Прежде чем вызвать функцию нужно написать ее прототип (описание функции).
Вообще говоря, есть два пути:
1) указать прототип функции перед мейном, а саму функцию - после. это позволяет сохранить в какой-то мере последовательность кода.
2) написать всю функцию перед мейном, а на прототип - вообще забить.
К.О.: Но на деле получается так, что если у вас нет кучи вложенных функций, то прототипы вообще не нужны. В обратном случае прототипы понадобятся вне зависимости, перед мейном написаны сами функции или нет.
void f( int ); // это прототип
void main( void )
{
int l = 2;
f( l );
}
// -----------------------------
void f( int x ) // это функция
{
printf( "%d", x );
}
по тетрадке здесь вроде все, но я хочу добавить пару примеров.
Пример 1.
#include <stdio.h>
/* прототип функции. в принципе, можно было не думать, а просто
скопировать "int quad( int p )" и поставить точку с запятой в конце,
но четкий вариант - еще убрать имена параметров: */
int quad( int );
void main()
{
int x, y; // есть целые х и y
x = 2; // x у нас равен двойке
y = quad( x ); // после вызова нашей функции y становится равным тому, что она возвращает
printf( "%d\n", y ); // выводим y - он равен четверке
y = quad( y ); // вызываем функцию от y - четыре в квадрате - 16
printf( "%d\n", y ); // выводим y, на экране видно 16
printf( "%d\n", quad(15) ); // выводим на экран квадрат 15, т.е. 225
if( quad(x) == quad(y) ) // использование в проверке
{
puts( "квадрат x = квадрату y" );
}
/* а вот, довольно-таки прикольный пример использования сей
функции в цикле for(). В итоге получаем список квадратов чисел от
1 до 32. так-то. */
for( x=1; x<=32; x++ )
printf( "y = %d\n", quad(x) );
getch();
}
int quad( int p )
{
int t;
t = p * p;
return t;
}
28. Функции без аргументов.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
29. Использование указателей в качестве параметров функций.
Использование указателей в качестве параметров функции оправдано когда необходимо модифицировать параметры, передать массив или его части.
void f( int*, int* )
void main( )
{
int x = 5, y = 10;
printf( "x = %d, y = %d \n", x, y );
f( &x, &y )
printf( "x = %d, y = %d \n", x, y );
}
void f( int *y, int *x )
{
int t;
t = *y;
// ололо здесь какая-то байда с параметрами, я ее не записал)
// ну, допустим (на самом деле это не так уж и важно):
t++;
*x = 100500;
}
Если в качестве параметров функции используется массив, то внутрь попадает начальный адрес массива. (К.О.: адрес первого элемента этого массива)
void f( int *, int );
// in the begining...
30. Функции для строк.
Для работы со строковыми функциями типа strcpy() нужно включить заголовочный файл STRING.H с помощью следующей строки:
#include <string.h>
1) strlen( строка )
эта функция вернет длину строки в символах (без нулевого байта). таким образом, strlen("hello") вернет 5.
2) strcpy( destination, source )
Оператор присваивания для строк не определен. Если c1 и c2 - символьные массивы, вы не сможете скопировать один в другой так:
c1 = c2; // так нельзя
Чтобы скопировать одну строку в другую, вместо использования оператора присваивания вызовите функцию копирования строк strcpy().
strcpy(c1,c2); // четкий и верный годный вариант
Оператор копирует символы, адресуемые указателем c2, в память, адресуемую указателем c1, включая нулевые байты.
31. Причины появления ошибок в программах.
1)неверное понимание поставленной задачи, приводит к решению другой задачи.
2)Неверная разработка спецификаций алгоритма может привести к правильному результату лишь для некоторых подмножестввсех данных.
3)неверное понимание используемых средств языка программирования может ввести ошибку при разработке код. алгоритма.
4)При вводе программы в компьютер можно ввести ошибки типа “опечатки”.
5)неправильный набор исходных данных при выполнении программы, приводит к получению неверных результатов или аварийному закрытию программы.
32. Тесты. Отладка программ.
33. Проверка программ «вручную». Анализ программ.
34. Проверка программ «вручную». Прокрутка.
Основные методы выявления ошибок является тестирование и отладка.
Тестирование: выявление ошибки
Отладка: устранение ошибки
Тестирование есть компьютерное и ручное.
Ручное(анализ)-проверка алгоритма по тексту без использования компьютера.
Анализ выполняется в несколько этапов:
1)проверка описания данных
2)Проверка правильности обработки данных
3)проверка вычислит функций
4)проверка логики (циклы!!!)
5)проверка интерфейса между функциями
6)проверка ввод\вывод
7)проверка помеха-защита