Как ввести строку программы в память

В программе строки могут определяться следующим образом:

  • как строковые константы;
  • как массивы символов;
  • через указатель на символьный тип;
  • как массивы строк.

Кроме того, должно быть предусмотрено выделение памяти для хранения строки.

Любая последовательность символов, заключенная в двойные кавычки «» , рассматривается как строковая константа .

Для корректного вывода любая строка должна заканчиваться нуль-символом ‘’ , целочисленное значение которого равно 0. При объявлении строковой константы нуль-символ добавляется к ней автоматически. Так, последовательность символов, представляющая собой строковую константу, будет размещена в оперативной памяти компьютера, включая нулевой байт.

Под хранение строки выделяются последовательно идущие ячейки оперативной памяти. Таким образом, строка представляет собой массив символов. Для хранения кода каждого символа строки отводится 1 байт.

Для помещения в строковую константу некоторых служебных символов используются символьные комбинации. Так, если необходимо включить в строку символ двойной кавычки, ему должен предшествовать символ «обратный слеш»: ‘»‘ .

КАК РАБОТАЮТ КОДИРОВКИ | ОСНОВЫ ПРОГРАММИРОВАНИЯ

Строковые константы размещаются в статической памяти. Начальный адрес последовательности символов в двойных кавычках трактуется как адрес строки. Строковые константы часто используются для осуществления диалога с пользователем в таких функциях, как printf() .

При определении массива символов необходимо сообщить компилятору требуемый размер памяти.

Компилятор также может самостоятельно определить размер массива символов, если инициализация массива задана при объявлении строковой константой:

char m2[]= «Горные вершины спят во тьме ночной.» ;
char m3[]=< ‘Т’,’и’,’х’,’и’,’е’,’ ‘,’д’,’о’,’л’,’и’,’н’,’ы’,’ ‘,’п’,’о’,’л’,’н’,’ы’,’ ‘,’с’,’в’,’е’,’ж’,’е’,’й’,’ ‘,’м’,’г’,’л’,’о’,’й’,’’ >;

В этом случае имена m2 и m3 являются указателями на первые элементы массивов:

  • m2 эквивалентно m3[0]
  • m3[2] эквивалентно ‘x’

При объявлении массива символов и инициализации его строковой константой можно явно указать размер массива, но указанный размер массива должен быть больше, чем размер инициализирующей строковой константы:

char m2[80]= «Горные вершины спят во тьме ночной.» ;

Для задания строки можно использовать указатель на символьный тип .

В этом случае объявление массива переменной m4 может быть присвоен адрес массива:

m4 = m3;
*m4 эквивалентно m3[0]= ‘Т’
*(m4+1) эквивалентно m3[1]= ‘и’

Здесь m3 является константой-указателем. Нельзя изменить m3 , так как это означало бы изменение положения (адреса) массива в памяти, в отличие от m4 .

Для указателя можно использовать операцию увеличения (перемещения на следующий символ):

Массивы символьных строк

Иногда в программах возникает необходимость описание массива символьных строк . В этом случае можно использовать индекс строки для доступа к нескольким разным строкам.

Как получить от пользователя строку с пробелами

char *poet[4] = < «Погиб поэт!», «- невольник чести -» ,
«Пал,» , «оклеветанный молвой…» >;

В этом случае poet является массивом, состоящим из четырех указателей на символьные строки. Каждая строка символов представляет собой символьный массив, поэтому имеется четыре указателя на массивы. Указатель poet[0] ссылается на первую строку:
*poet[0] эквивалентно ‘П’,
*poet[l] эквивалентно ‘-‘.

Инициализация выполняется по правилам, определенным для массивов.
Тексты в кавычках эквивалентны инициализации каждой строки в массиве. Запятая разделяет соседние
последовательности.
Кроме того, можно явно задавать размер строк символов, используя описание, подобное такому:

char poet[4][23];

Разница заключается в том, что такая форма задает «прямоугольный» массив, в котором все строки имеют одинаковую длину.

Массив строк

Свободный массив

сhar *poet[4];

определяет свободный массив, где длина каждой строки определяется тем указателем, который эту строку инициализирует. Свободный массив не тратит память напрасно.

Операции со строками

Большинство операций языка Си, имеющих дело со строками, работает с указателями. Для размещения в оперативной памяти строки символов необходимо:

  • выделить блок оперативной памяти под массив;
  • проинициализировать строку.

Для выделения памяти под хранение строки могут использоваться функции динамического выделения памяти. При этом необходимо учитывать требуемый размер строки:

char *name;
name = ( char *)malloc(10);
scanf( «%9s» , name);

Для ввода строки использована функция scanf() , причем введенная строка не может превышать 9 символов. Последний символ будет содержать ‘’ .

Функции ввода строк

Для ввода строки может использоваться функция scanf() . Однако функция scanf() предназначена скорее для получения слова, а не строки. Если применять формат «%s» для ввода, строка вводится до (но не включая) следующего пустого символа, которым может быть пробел, табуляция или перевод строки.

Для ввода строки, включая пробелы, используется функция

char * gets( char *);

или её эквивалент
char * gets_s( char *);

В качестве аргумента функции передается указатель на строку, в которую осуществляется ввод. Функция просит пользователя ввести строку, которую она помещает в массив, пока пользователь не нажмет Enter.

Функции вывода строк

Для вывода строк можно воспользоваться рассмотренной ранее функцией

printf( «%s» , str); // str — указатель на строку

или в сокращенном формате

Для вывода строк также может использоваться функция

int puts ( char *s);

которая печатает строку s и переводит курсор на новую строку (в отличие от printf() ). Функция puts() также может использоваться для вывода строковых констант, заключенных в кавычки.

Функция ввода символов

Для ввода символов может использоваться функция

char getchar();

которая возвращает значение символа, введенного с клавиатуры. Указанная функция использовалась в рассмотренных ранее примерах для задержки окна консоли после выполнения программы до нажатия клавиши.

Функция вывода символов

Для вывода символов может использоваться функция

char putchar( char );

которая возвращает значение выводимого символа и выводит на экран символ, переданный в качестве аргумента.

Пример Посчитать количество введенных символов во введенной строке.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

#include
#include
#include
int main() char s[80], sym;
int count, i;
system( «chcp 1251» );
system( «cls» );
printf( «Введите строку : » );
gets_s(s);
printf( «Введите символ : » );
sym = getchar();
count = 0;
for (i = 0; s[i] != ‘’ ; i++)
if (s[i] == sym)
count++;
>
printf( «В строкеn» );
puts(s); // Вывод строки
printf( «символ » );
putchar(sym); // Вывод символа
printf( » встречается %d раз» , count);
getchar(); getchar();
return 0;
>

Количество введенных символов в строке

Результат выполнения

Основные функции стандартной библиотеки string.h

Основные функции стандартной библиотеки string.h приведены в таблице.

char *strcat( char *s1, char *s2)
char *strncat( char *s1, char *s2, int n)
char *strсpy( char *s1, char *s2)
char *strncpy( char *s1, char *s2, int n)
int strcmp( char *s1, char *s2)
int strncmp( char *s1, char *s2, int n)
int strlen( char *s)
char *strset( char *s, char c)
char *strnset( char *s, char c, int n)

Читайте также:
Программа для того чтобы ставили лайки

Пример использования функций

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
int main() char m1[80] = «Первая строка» ;
char m2[80] = «Вторая строка» ;
char m3[80];
system( «chcp 1251» );
system( «cls» );
strncpy(m3, m1, 6); // не добавляет ‘’ в конце строки
puts( «Результат strncpy(m3, m1, 6)» );
puts(m3);
strcpy(m3, m1);
puts( «Результат strcpy(m3, m1)» );
puts(m3);
puts( «Результат strcmp(m3, m1) равен» );
printf( «%d» , strcmp(m3, m1));
strncat(m3, m2, 5);
puts( «Результат strncat(m3, m2, 5)» );
puts(m3);
strcat(m3, m2);
puts( «Результат strcat(m3, m2)» );
puts(m3);
puts( «Количество символов в строке m1 равно strlen(m1) : » );
printf( «%dn» , strlen(m1));
_strnset(m3, ‘f’ , 7);
puts( «Результат strnset(m3, ‘f’ , 7)» );
puts(m3);
_strset(m3, ‘k’ );
puts( «Результат strnset(m3, ‘k’ )» );
puts(m3);
getchar();
return 0;
>

Использование функций

Результат выполнения

Комментариев к записи: 132

Елена,здравствуйте.Опять не могу решить задачу.Текст слов разделенных пробелами.Вывести самое короткое(самое длинное)слово. Код СИ.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

while ((c=getchar())!=EOF)
< n++; //п-число символов введенных.
a[n]=c; // массив символов.
if (c==10)c=32;
if (c==32) // i-число символов в слове(длина слова).
else continue;
n=-1;

Работает не нормально.В чем ошибка? Спасибо.

Зачем так сложно сравнивать длины слов? Набрали массив из n символов до пробела. if(n>max) То же с минимумом. Ещё не забывайте, что переход на новую строку — это пара символов с кодами 13 и 10. На 10 Вы проверили, а про 13 забыли.

Елена,спасибо.

Елена, здравствуйте.Опять я забуксовал на книжней задаче. Учу СИ по книге Д.Ритчи.Пытаюсь скомпилировать задачу по строкам в 4-х компилятора ошибки на неё.В авторском варианте ни где запустить не смог.У меня вопрос- книга старая,сменился стандарт СИ или это ещё что-то. И главный вопрос эта задача работает с 2-мя строками или со всеми введенными? Текст задачи.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#include
#define MAXLINE 1000
int getline( char line[], int MAXLINE);
void copy ( char to[], char from[]);
int main () < int len,max;
char line[MAXLINE];
char longest[MAXLINE];
max=0;
while ((len =getline(line,MAXLINE))>0)
if (len>max)copy(longest,line);>
if (max>0) printf( «%s» ,longest);
return 0; >
int getline ( char s[] , int lim) int c,i ;
for (i=0;i
s[i]=c;
if (c==’n’)
s[i]=’’; return i; >
void copy( char to[], char from[])
< int i;i=0;
while ((to[i]=from[i])!=’’) i++;>

Елена,здравствуйте.Начал учить СИ и столкнулся с неприступной для меня задачей-как н-количество символов одинаковых и рядом стоящих заменить одним таким же символом? Задача книжная в самом начале,где ещё не дошли до массивов.

Как без массивов решать — не знаю, честно скажу. Скажите хотя бы, как хранятся без массива рассматриваемые символы

Елена,здравствуйте. Вчера написал сообщение, но оно так и не появляется. Выделенные символы могу выделить, но один потом вернуть не могу. Делаю через getchar i printf. Если не затруднит как реализовать это через массивы.

Код не надо- на словах если можно.Спасибо.

Источник: prog-cpp.ru

5 Ввод программы в память компьютера. Пробный запуск

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

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

6. Отладка и тестирование программы

Процесс поиска и исправления ошибок в программе называется отладкой. Ошибки могут возникнуть при наборе, в результате нарушения правил записи программ на языке программирования – так называемыесинтаксическиеошибки.

Обнаружить и исправить их помогают специальные инструментальные программы (программы синтаксического контроля), входящие в состав системы программирования (см. § 4.1). Система анализирует программу и выдает сообщение о месте и характере ошибки. Часто ошибки связаны с тем, что некоторая синтаксически правильная конструкция не может быть выполнена (например, деление на нуль или попытка присвоить величине целого типа вещественное значение). В этом случае также появляется сообщение о причине отказа и указывается, какая именно команда не может быть выполнена.

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

Важным этапом процесса отладки является тестированиепрограммы, т.е. испытание ее путем введения теста – определенного набора исходных данных, для которого результат работы отдельных блоков или программы в целом известен заранее.

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

Умение удачно подобрать такой тест, при котором ошибка (если она есть) наиболее вероятна, и предусмотреть разнообразные варианты хода вычислительного процесса, а также действия пользователя (порой весьма непредсказуемые), и, следовательно, защитить работу программы от всяких неожиданностей – большое искусство программиста.

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

До последнего времени 4, 5 и 6 этапы были необходимыми этапами решения задачи с помощью ЭВМ. При этом языки и системы программирования были теми программными инструментами, с помощью которых создавались новые программы для решения задач пользователя. Однако с расширением круга задач, для решения которых используется компьютер, растет число людей, которые, не будучи профессиональными программистами, применяют компьютер в своей работе.

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

Читайте также:
Программа для контроля чем занимаются сотрудники

В процессе построения информационной модели задачи пользователь определяет, какие действия ему потребуется выполнить для достижения результата, и в соответствии с этим решает, каким программным средством воспользоваться. Если в его распоряжении имеется программа, подходящая для решения данной задачи, то пользователь выбирает ее в качестве инструмента (СУБД, табличный процессор, математический пакет и др.). Если же готовым прикладным программным средством воспользоваться нельзя, придется использовать технологию программирования.

Источник: studfile.net

Lerbytech / string_array_example.c

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters

#include
#include
#include
#include
int main ()
// НУЖНЫЕ НАМ ПЕРЕМЕННЫЕ.
//Это универсальный набор, минимально необходимый для любой задачи с массивом строк
char * STR [ 10 ]; // наш массив строк
char * * s ; // указатель на массив. Обязательно двойной, не ошибайтесь
char buf [ 80 ]; // массив куда заносится введенная с клавиатуры консоль
int n = 0 ; // счетчик числа введённых строк
int max_number_of_strings = 10 ; // указываете сколько максимум строк хотите ввести(опционально)
// ПРОЦЕДУРА ВВОДА
// если хотите чтобы можно было вводить сколько угодно строк, пока не будет введена нулевая, поправьте условие цикла на:
// *gets(buf) != ‘’
for ( s = STR ; n < max_number_of_strings * gets ( buf ) != ‘’ ; n ++ , s ++ ) < //считываем данные в buf
* s = ( char * ) malloc ( strlen ( buf ) + 1 ); //выделяем память в массива строк s
strcpy ( * s , buf ); //копируем данные из buf в свежевыделенную память
>
printf ( «———————n» ); // сделаем разбиение для красоты
// ВЫВОД НА ЭКРАН
// обратите внимание на условие цикла. Если будете менять кол-во строк в массиве, обязательно изменяйте значение переменной n
for ( s = STR ; s < STR + n ; s ++ )
puts ( * s ); //выводим все подстроки
return 0 ;
>

Lerbytech commented Nov 26, 2017

Объяснение на пальцах того, как работать с массивом строк.

Логические блоки:

  1. Числовые матрицы
  2. Массивы строк
  3. Ввод и вывод (пример)

1. Числовые матрицы

Чтобы понять массивы строк вспомним второй блок задач задач про числовые матрицы. Обычно мы считали их квадратными, но я буду предполагать что они могут быть прямоугольными.
ТВ показывала различные варианты объявления матрицы. Рассмотрим их ещё раз.

Проще всего объявить через индексы:
0> int Mat[10][10];

Такой вариант объявления матрицы даёт нам фиксированную матрицу размером 10 на 10. Изменить его в ходе работы нельзя. В памяти будет выделено W*H*sizeof(int) байт. Отметим что матрице блок памяти выделяется последовательно. Очевидно что для большой матрицы вы можете столкнуться с некоторыми проблемами — она может в целом влезать в память, но вот однородного свободного блока для неё не будет .
Зато обращение к элементу производится легко и просто (за что все индексы и любят):
1> int N = Mat[0][1]; // 0 строка, 1 столбец

Другой вариант объявления матрицы который вы проходили заключался в объявлении массива указателей вот такого вида:
2> int *Arr[10]; // массив из 10 указателей типа integer

Объявляется массив указателей из 10 элементов. Каждый элемент — указатель, который будет дальше указывать на какую-либо строку матрицы.
Сразу заметим, что у вас не может быть больше 10 строк, так как на 11 физически нет места в массиве в виде свободного указателя. С другой стороны, в памяти пока что занято место только под эти 10 указателей (уже меньше, чем в прошлом примере, верно?).
Как же выделить место под каждую строчку матрицы шириной в W столбцов? Да легко, каждому указателю из массива Arr можно выделить память через malloc.
3>

int i = 0; for (i = 0; i H; i++) Arr[i] = (int*)malloc( sizeof(int) * W);

В чём преимущество данного подхода?
В первую очередь, это не фиксированный размер матрицы. Можно выделить сколько угодно места под каждую строчку, то есть матрицу можно легко сделать неквадратной и даже определить кол-во столбцов в ходе работы программы.
Во-вторых, вы можете даже не использовать все 10 указателей под каждую строчку. В общем, по памяти это оптимальнее.

С другой стороны, простота данного подхода является мнимой. Если вам понадобится больше 10 строк, то ваш массив Arr не подойдет по размеру. Можно выделить и больший размер, но где потолок? 20? 100? 1000?

Всегда у вас либо не хватает, либо вы берёте с избытком.
Откровенно говоря, эта проблема немного надуманная. Когда вы реально с ней столкнетесь, то будете знать много больше чем сейчас и заботить вас будут другие вещи. С другой стороны, из спортивного интереса и чувства вселенской справедливости, было бы неплохо научиться делать всё в виде чистой динамики.
Так что нет места полумерам! Мы можем объявить полностью динамически определяемую матрицу! Для этого введем двойной указатель.

4>

int **Mat; int W, H; //ширина и высота W = 10; H = 10; Mat = (int**)malloc(sizeof(int*) * H); // выделяем память под указатели на строки матрицы int i = 0; // заводим счетчик для смещения по каждой строке for ( i = 0; i H; i++) *(Mat + i) = (char*)malloc(sizeof(int) * W); // выделяем память каждой строке под хранимые в ней элементы

Код выше — абсолютная динамика. Размеры матрицы задаются в любом месте программы. Да, двойной указатель может казаться страшным. Но он точно выглядит менее уродским, чем конструкции массивов указателей. С другой стороны, массивы указателей достаточно часто используются в программах Жуковой и, вероятно, она будет ожидать увидеть именно их.
Важно понимать, что и двойной указатель, и массив указателей взаимозаменяемы.

int **Mat;
int *Arr[4];
// пропустим код где внесли значения в Mar и Arr

Обратимся к элементу в второй строчке и втором столбце. Для этого через двойной указатель *( (*Mat + 1) + 2) , а через массив — *(*(Arr[1]) + 2). Как видно, разницы при работе между ними почти нет.

Пытливый читатель может задаться вопросом — как это связано с строками? Ответ: самым очевидным образом.
Строка представляется как массив символов. С ней удобно работать через указатели.
Пусть вы вводите массив строк. Заранее количество вводимых строк скорее всего вам неизвестно. Каждая строка имеет различное число элементов. Работать через двойной указатель в этих условиях проще всего. Но сегодня здесь будет описана только работа через массив строк.
Просмотрите ещё раз код программы на самом верху страницы прежде чем начать читать следующий раздел.

2. Массивы строк

image

Обычная строка в памяти представляется как массив символов. Все элементы лежат последовательно.

image

Если вы объявляете указатель, то под него тоже выделяется ячейка памяти.
Когда вы «выделяете ему память» и вносите в эту память значения, то на заранее неизвестном свободном участке памяти будет «огорожен» участок, в которой будут внесены значения массива.
Блок памяти и участок необязательно расположены рядышком.

Читайте также:
Как открыть программу криптопро

image

Когда же вы выделяете массив указателей, то в памяти это выглядит примерно так:

Обсудим эту картинку подробнее.
Задан массив указателей, указателям заданный строки. Хотим найти длину строки 2 ( one ) с помощью strlen
Обратимся я ячейке Arr[1] и произведем разыменовывание ( *(Arr[1]) ). Как компьютер поймет сколько в полученной строке символов?
Массив указателей хранит адреса блоков памяти, а именно — адреса первых ячеек каждого блока. При разыменовании указателя компьютер берет адрес хранящийся в указателе(1), переходит по нему на нужный блок памяти (2) и считывает все ячейки по возрастанию пока не встретит ‘’ — нуль-терминирующий символ(3) [подробнее об этом — http://qoo.by/321t]

То есть, заданный в программе массив указателей даёт нам кучку указателей, для каждого из которых можно выделить память, заполнить её значениями и работать с ними. Для простоты, можно считать, что в каждой ячейке массива хранится строка.

3. Ввод массива строк

Рассмотрим подробнее что происходит в нашей программе-примере.
Программа выполняет следующее: пользователь вводит строку, то есть последовательность символов и жмет enter. Эта последовательность записывается в память. Если пользователь ввёл пустую строку (просто нажал enter), то ввод считается законченным. После чего на экран выводятся записанные в память строки.

Теперь построчно:
char *STR[10]; — массив указателей. Каждому указателю будет выделена память, куда будет записана введенная строка.
char **s; — указатель на строку из массива. С его помощью в цикле будем обращаться к нужной строке. Обязательно двойной: первый уровень позволяет обратиться к элементу массива, а второй уровень должен совпадать с типом строки _char*_
char buf[80]; — массив фиксированной длины, в который заносится введенная с клавиатуры строка. Можете использовать и char*, но проще через массив ( по не до конца понятным мне причинам если использовать строку возникают непонятные глюки. С массивом такой байды нету + Жукова обычно пишет массив она что-то знает ). Обратите внимание — в массиве 80 элементов, то есть строка большей длины записана не будет. Функция gets() передаст всю введенную строку в этот массив, но поместятся только первые 80.
int n = 0; — счетчик числа введенных строк.
int max_number_of_strings = 10; — указываете сколько максимум строк хотите ввести. Счетчик количества строк не превысит это значение.

Для того, чтобы работать с строкой мы будем пользоваться переменной **s — она имеет такой же тип данных, как и наш массив указателей (для людей это разное, для компьютера одно и то же).
Перед началом работы укажем: s = STR
В дальнейшем после каждой итерации цикла ввода (то есть, после каждой успешно введенной строки) будем увеличивать эту переменную: s++

Так как ввод строк осуществляется в цикле, то обсудим условия выхода из него. Их ровно два:

  1. Массив указателей заполнен
  2. Введена пустая строка

С первым условие проблем нет: у нас есть счётчик n и условие n < max_number_of_strings подойдет под наши задачи.
С вторым условием немножко сложнее.
Строка считывается функцией gets(char*) . Аргумент функции — это переменная в которую мы хотим записать пользовательский ввод. Будем записывать в наш массив buf (то есть buffer // буфер):
gets(buf)
Если пользователь ввёл пустую строку, то в строке будет записан только ‘’ . В случае нашего буфера мы говорим о ячейке buf[0] .
Второе условие можно записать следующим образом: buf[0] != ‘’

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

for ( s = STR, n = 0; n max_number_of_string; s++) gets(buf); if (buf[0] == ‘’) break; // если встретили пустую строку, то дальнейшая работа цикла не нужна // дальше записываем строчку в STR[i] n++; // так как считали строчку успешно, то увеличим счётчик строк на единичку >

Язык Си очень хитёр. Формально, к каждой функции можно обратиться по указателю и тип void — не исключение. Есть хитрая возможность повыё******ся оптимизировать работу цикла и сделать его ещё более непонятным .
Мы можем обратиться к функции gets(buf) через разыменовывание и, тем самым, получим доступ к считанной ей строке. Этот доступ указывает сразу на начало строки, которое совпадает с первым элементом. Сравниваем его с символом конца строки и дело в шляпе. Наш счётчик n тоже можно вынести в цикл.
Из таких соображений мы получаем цикл:
for (s = STR, n = 0; n < max_number_of_strings *gets(buf) != ‘’; n++, s++)

Теперь рассмотрим как записать в память нашу считанную строку. Сейчас (после выполнения gets(buf) ) она хранится в buf
Нам необходимо нужному(!) указателю из нашего массива указателей STR выделить память подходящего размера и в эту память записать значения buf .
Для выделения памяти воспользуемся malloc :
*s= (char*)malloc( strlen(buf) * sizeof(char) + 1)
В первую очередь, обратите внимание что вы выделяем память не s, а хранимому в ней значению. То есть, мы берем наш указатель из массива STR на который сейчас указывает s и ему(!) выделяем память. Соответственно в скобочках перед malloc пишем одну звездочку, а не две (так как строка — это char* , а не char** )
Для выделения памяти нам нужно знать сколько её выделять, то есть — нужно найти длину строки buf воспользовавшись strlen . Эта функция вернем нам количество символов, но не учтёт нуль-символ. Его придется добавить вручную — просто увеличим +1 объем памяти. Обратите внимание на эту деталь, так убережёте себя от кучи убитых часов на отладку.

Теперь остается скопировать нашу строчку из временного места хранения в постоянное. Вызываем strcpy :
strcpy(STR[i], buf).

И на этом всё! В полном виде наш цикл устроен так:

for (s = STR; n max_number_of_strings *gets_s(buf) != ‘’; n++, s++) //считываем данные в buf *s = (char*)malloc(strlen(buf) + 1); //выделяем память в массива строк s strcpy(*s, buf); //копируем данные из buf в свежевыделенную память >

Обсудим вывод строки. Он полностью аналогичен работе с массивами (ну или работе с строками, кому как угодно). Мы знаем сколько строк введено. Берем указатель S , связываем его с массивом и выводим на экран все первые n элементов.
Один нюанс: наш s формально указывает на указатель в массиве, а не на строчку. Строка же — это то, что хранится в том блоке памяти, на который указывает указатель. Поэтому воспользуемся разыменованием чтобы получить нашу строчку.
( Компилятор вам сразу выдаст подсказку: функция puts принимает на вход char* , а тип s — char** .

for (s = STR; s STR + n; s++) puts(*s);

Источник: gist.github.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru