4.1.Указатели и аргументы функции
Переменные передаются функции по значению, поэтому нет прямого способа в вызванной функции изменить некоторую переменную в вызвавшей функции. Однако это легко сделать, если передавать функции не переменные, а их адреса. Программа Р20 иллюстрирует использование указателей в качестве аргументов функции izm(). Вначале в ней вводятся некоторые значения переменных а и b, затем они меняются местами. Заметим, что если в main() a и b – это переменные, то в izm() – это уже адреса, а значения переменных по этим адресам будут соответственно *а и *b. Пример программы Р20:
/*Программа Р20. Указатели и аргументы функций*/
#include<stdio.h>
main(){
int a, b;
puts(“введите значения а, b”);
scanf(“%d%d”, &a, &b);
printf(“a=%d, b=%d\n”, a, b);
izm(&a, &b); /*функция izm() меняет местами элементы а и b; ей передаются адреса этих элементов*/
printf(“измененные значения: a=%d; b=%d”, a, b);
}
#include “izm.c”
izm(a, b);
int *a, *b;
{
int c; /*a и b – указатели, *а и *b – значения, на которые они указывают*/
c=*a; *a=*b; *b=c;
}
Результат выполнения программы:
Введите значения a, b
87 999
a=87, b=999
измененные значения: a=999; b=87
4.2.Адресная арифметика
Если адреса указывают на элементы одного массива, то их можно сравнивать. Нельзя сравнивать либо использовать в арифметических операциях указатели на разные массивы. Любой адрес можно провеять на равенство или неравенство значению NULL, которое записывается вместо нуля (NULL можно присваивать указателю). Программа Р22 демонстрирует операции адресной арифметики.
/*Программа Р22. Адресная арифметика и операции с массивами*/
#include<stdio.h>
int a[]={10, 20, 30, 40 50, 60};
main(){
int i, *p;
for(i=0; i<6; i++) printf(“a[%d]=%d; %c”, i, a[i], (i==2)?’\n’:’ ‘);
printf(“\n\n”); /*вывод на экран массива а*/
for(p=&a[0]; p<=a[5]; p++) printf(“значение *p: %d; %c”, *p, (p==&a[2])?’\n’:’ ‘);
printf(“\n\n”); /*другой вариант вывода на экран массива а*/
for(p=&a[0], i=0; i<6; i++) printf(“p[$d]=%d; %c”, I, p[i], (i==2)?’\n’:’ ‘);
printf(“\n\n”); /*другой вариант вывода на экран массива а*/
for(p=a, i=0; p+i<=a+4; p++, i++) printf(“*(p+%d)=%d\t”, I, *(p+i));
printf(“\n\n”); /*вывод на экран 0-го, 2-го и 4-го элементов массива а*/
for(p=a+5; p>=a; p--) printf(“значение *p: %d; %c”, *p, (p==a+3)?’\n’:’ ‘);
printf(“\n\n”); /*Вывод на экран массива а в обратном порядке*/
for(p=a+5, i=0; i<=5; i++) printf(“p[-%d]= %d; %c”, i, p[-i], (i==2)?’\n’:’ ‘);
printf(“\n\n”); /*другой вариант вывода на экран массива а в обратном порядке*/
for(p=a+5; p>=a; p--) printf(“значение a[p-a]: %d; %c”, a[p-a], ((p==a+4)||(p==a+2))?’\n’:’ ‘);
printf(“\n\n”); /*Еще один вариант вывода на экран массива а в обратном порядке*/
}
Результаты работы программы Р22:
a[0]=10; a[1]=20; a[2]=30;
a[3]=40; a[4]=50; a[5]=60;
значение *р: 10; значение *р: 20; значение *р: 30;
значение *р: 40; значение *р: 50; значение *р: 60;
p[0]=10; p[1]=20; p[2]=30;
p[3]=40; p[4]=50; p[5]=60;
*(p+0)=10 *(p+1)=30 *(p+2)=50;
значение *р: 60; значение *р: 50; значение *р: 40;
значение *р: 30; значение *р: 20; значение *р: 10;
p[-0]=60; p[-1]=50; p[-2]=40;
p[-3]=30; p[-4]=20; p[-5]=10;
значение a[p-a]: 60; значение a[p-a]: 50;
значение a[p-a]: 40; значение a[p-a]: 30;
значение a[p-a]: 20; значение a[p-a]: 10;
4.3.Массивы указателей
В языке допускаются массивы указателей, которые объявляются следующим образом: char *m[5];. Здесь m[5] – массив, содержащий указатели на элементы типа char. Программа Р26 осуществляет упорядочивание строк заданного массива s в порядке убывания кодов первой буквы. Пусть в s 5 строк. Введем массив m указателей на строки массива s. Тогда для упорядочения s дочтаточно переставить надлежащим образом указатели в m.
/*Программа Р26. Массив указателей*/
#include<stdio.h>
main(){
int i, j, q, ind[5]={0, 0, 0, 0, 0}; /*ind – вспомогательный массив*/
char p, s[5][20], *m[5];
printf(“ввести 5 строк символов\n”);
for(i=0; i<5; i++) {scanf(“%s”, s[i]); m[i]=&s[i][0];} /*массив m будет содержать адреса строк массива s*/
for(i=0; i<5; i++) printf(“строка - %d; адрес строки - %p\n”, i, m[i]);
for(i=0; i<5; i++){p=’A’; q=0; /*переменной р присваивается символ А с заведомо малым кодом (А – русская буква)*/
for(j=0; j<5; j++) if(s[j][0]>=p && ind[j]==0){p=s[j][0]; q=j;}
ind[q]=1; /*после выполнения вложенного цикла for q равно номеру строки с наибольшим кодом первого символа; ind – вспомогательный массив, используемый для исключения повторного обращения к выбранной строке*/
m[i]=&s[q][0];}
puts(“\nупорядоченные строки”);
for(i=0; i<5; i++) printf(“строка %d\t\%s\n”, I, m[i]);
}
Результат работы программы:
Ввести 5 строк символов
Женя
Ваня
Петя
Миша
Гриша
Строка – 0; адрес строки – FF74
Строка – 1; адрес строки – FF88
Строка – 2; адрес строки – FF9C
Строка – 3; адрес строки – FFB0
Строка – 4; адрес строки – FFC4
Упорядоченные строки
Строка – 0; Петя
Строка – 1; Миша
Строка – 2; Женя
Строка – 3; Гриша
Строка – 4; Ваня
Следующая программа Р23 демонстрирует использование массива указателей на строки 2-мерного массива а.
/*Программа Р23. Указатели в многомерном массиве */
#include<stdio.h>
int a[3][3]={{10, 20, 30},
{40, 50, 60},
{70, 80, 90}};
int *pa[3]={a[0], a[1], a[2]}; /*объявление и инициализация указателя на строки массива а и присвоение начальных значений pa[0]=a[0]; pa[1]=a[1]; pa[2]=a[2]*/
int *p=a[0]; /*объявление указателя р на нулевой элемент первой строки массива а*/
main(){
int i, j;
puts(“исходная матрица”);
for(i=0; i<3; i++){
for(j=0; j<3; j++) printf(“%d”, a[i][j]);
printf(“\n”); }
printf(“\n”);
for(i=0; i<3; i++) printf(“a[%d][2-%d]=%d;\t*a[%d]=%d; \t*(*(a+%d)+%d)=%d\n”, i, i, a[i][2-i], i, *a[i], i, i, *(*(a+i)+i));
/*вывод на экран значений диагональных элементов от a[0][2] до a[2][0] массива а (a[i][2-i]); вывод на экран значений первых элементов каждой строки массива а (*a[i]); вывод на экран значений i-х элементов i-й строки массива а (*(*(a+i)+i))*/
for(i=0; i<3; i++) printf(“*pa[%d]=%d;\tp[%d]=%d\n”, i, *pa[i], i, p[i]); /*вывод на экран значений первых элементов каждой строки массива а (*pa[i]); вывод на экран значений элементов первой строки массива а (p[i])*/
}
Результат выполнения программы:
Исходная матрица
10 20 30
40 50 60
70 80 90
a[0][2-0]=30; *a[0]=10; *(*(a+0)+0)=10
a[1][2-1]=50; *a[1]=40; *(*(a+1)+1)=50
a[2][2-2]=70; *a[2]=70; *(*(a+2)+2)=90
*pa[0]=10; p[0]=10
*pa[1]=40; p[1]=20
*pa[2]=70; p[2]=30
Следующая программа Р24 сравнивает 2 строки str1 и str2.
/*Программа Р24. Ссылки на символьные массивы*/
#include<stdio.h>
main(){
int sravnenie();
char str1[30], str2[30];
printf(“ввести строки str1, str2\n”);
scanf(“%s%s”, str1, str2);
printf(“строка 1 - \t%s\n”, str1);
printf(“строка 2 - \t%s\n”, str2);
printf(“результат сравнения - \t%d”, sravnenie(str1, str2)); /*обращение к функции sravnenie() и вывод результата сравнения*/
}
sravnenie(s1, s2); /*функция возвращает отрицательное значение, если лексикографически s1<s2, положительное значение, если s1>s2, нулевое значение, если s1=s2*/
char *s1, s2;
{for(; *s1==*s2; s1++, s2++) if(*s1==’\0’) return(0);
return(*s1-*s2);
}
Результат работы программы:
Введите строки str1, str2
Петя
Иванов
Строка 1 – Петя
Строка 2 – Иванов
Результат сравнения – 7
Программа Р25 показывает использование многомерных массивов. В нее вводится матрица из нулей и единиц. Программа находит номер строки с наибольшим числом единиц.
/*Программа Р25. Многомерные массивы*/
#include<stdio.h>
main(){
int I, j, k, l, p, q=0, f=0, m[8][10];
puts(“введите число столбцов и строк матрицы m”);
scanf(“%d%d”, &i, &j);
puts(“ввести матрицу m по строкам”);
for(k=0; k<j; k++)
for(l=0; l<i; l++) scanf(“%d”, &m[k][l]);
puts(“введенная матрица m”);
for(k=0; k<j; k++)
for(l=0; l<i; l++) printf(“%d%c”, m[k][l], (l==i-1)?’\n’:’ ‘); /*используется тернарная операция “?:”*/
/*нахождение в матрице m строки с наибольшим числом единиц*/
for(k=0; k<j; k++){p=0;
for(l=0; l<i; l++) if(m[k][l]==1) p++
if(q<p){q=p; f=k;}} /*f – номер строки с наибольшим числом единиц, q – число единиц в f-й строке*/
printf(“номер строки с наибольшим числом единиц: %d;\nчисло единиц в строке:%d\n”, f+1, q);
}
Результат работы программы:
Введите число столбцов и строк матрицы m
4 3
Ввести матрицу m по строкам
1 0 0 1
1 0 1 1
0 1 0 1
Введенная матрица m
1 0 0 1
1 0 1 1
0 1 0 1
Номер строкис наибольшим числом единиц: 2;
Число единиц в строке: 3
Массив указателей можно инициализировать. Программа Р27 является соответствующим примером.
/*Программа 27. Инициализация массивов ссылок*/
#include<stdio.h>
main(){
int n;
char *name[]={“неверный номер месяца”, “январь”, “февраль”, “март”, “апрель”, “май”, “июнь”, “июль”, “август”, “сентябрь”, “октябрь”, “ноябрь”, “декабрь”};
puts(“введите номер месяца года”);
scanf(“%d”, &n);
printf(“название месяца – %s”, (n<1 || n>12)?name[0]: name[n]);
}
Результат работы программы:
Введите номер месяца года
10
Название месяца – октябрь
Указатели могут быть многоуровневыми, типа указатель на указатель, указатель на указатель на указатель и т.д.
4.6.Внешние аргументы
В программу на языке С можно передавать некоторые аргументы или параметры из командной строки. Когда, начиная вычисления, мы обращаемся к функции main(), ей передаются 2 параметра. Первый имеет имя argc и определяет число командных аргументов при обращении к программе. Второй, с именем argv, является указателем на массив символьных строк, содержащих эти аргументы (в одной строке – один аргумент). Предположим, что на диске В: есть некоторая программа P0.EXE. Обратимся к ней следующим образом:
B>P0 ВИТЯ ВОЛОДЯ БОРЯ
Тогда argv[0] – это указатель на Р0, argv[1] – на строку ВИТЯ и т.д. На первый фактический аргумент указывает argv[1], а на последний – argv[3]. Если argc=1, то после имени программы в командной строке параметров нет.
Следующие программы Р28 и Р29 показывают использование внешних аргументов. В первой из них командные параметры возвращаются на экран дисплея. Во второй, в зависимости от значения первого аргумента, последующие аргументы выводятся на экран в прямом или обратном порядке.
/*Программа 28. Использование внешних аргументов*/
#include<stdio.h>
main(argc, argv)