|
printf, напечатать массив символов |
|
|
|
Nov 14 2014, 23:37
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(Метценгерштейн @ Nov 15 2014, 02:30)  есть массив char, содержит 5 символов. никакого завершающего нуля нет. как мне его напечатать? Как строку, но с ограничителем в формате: char array[5] = {'a', 'b', 'c', 'd', 'e'} printf( "%5.5s\n", array); такой формат запретит печатать строку дальше 5-го символа, а потому будет не важно, есть в конце нуль или нет.
|
|
|
|
|
Nov 15 2014, 00:11
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(Метценгерштейн @ Nov 15 2014, 02:51)  а если у меня массив символов не всегда 5, а может 3 или 4 быть. То как? просто печать массива не вывести никак? если никак, то могу '\0' добавить концом Понятие длины массива в общем случае неопределено. Его имя тождественно указателю на начало, но где у него конец - обычно известно лишь программисту, но не компилятору. Впрочем, если массив задан так char array[5] = {'a', 'b', 'c', 'd', 'e'} то число элементов можно узнать, как sizeof(array), а потом столько раз прокрутить цикл, печатая по одному: for(int i=0; i < sizeof(array); i++) printf( "%с", array[i]); Символ же '\0' ни малейшего отношения к концу массива не имеет, поскольку может встретиться в любом его месте или не встретиться вообще. Однако он имеет отношение к символьным строкам (где байты - литеры): там он используется в качестве конца строки (но не перевода каретки!), поскольку символ с кодом '\0' изображения не имеет. Поэтому вам надо четко определиться с тем, что вы собираетесь распечатывать - массив со всеми его элементами, или строку до последнего глазами видимого знака. И это не одно и тоже, т.к. строка может быть короче массива, куда она была записана. В этом случае массив служит буфером для этой строки. P.S. Например, код char array[1000] = "text"; порождает массив длиной в 1000 байт, в котором заполнены (инициализированы) только первые 5 элементов: 4 буквы и '\0'. А за нулем и до самого конца - мусор. Вот и решайте, вам 4 буквы надо напечатать или все 1000 байт вместе с мусором?
|
|
|
|
|
Nov 15 2014, 09:52
|
Профессионал
    
Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079

|
Код #include <math.h> #include "stdafx.h" #include <iostream> // для русификации
unsigned int mass[10];
void main (void) { setlocale(LC_ALL, "Russian"); int z1; char str[] = "пр,алf,б,авпле,gkпроб,qwert."; char temp[6];
//printf("%s", temp);
for (int i = 0; i < sizeof(str); i++) { if (str[i] == ',') { z1 = i; // запомнили где запятая (начало слова) }
if ((str[i] >= 97) & (str[i] <= 122)) { for (int f = 0; f < 5; f++) { if ((str[(z1 + 1 + f)]) == ',') // дошли до второй запятой { //temp str[(z1 + 1 + f)] break; } char c = str[(z1 + 1 + f)]; printf("%c", c); }
}
} } на самой нижней printf выдает ошибку при компиляции. Что не так ему? код под visual studio все, разобрался, заработал код. Спасибо.
|
|
|
|
|
Nov 15 2014, 10:52
|
Профессионал
     
Группа: Модератор FTP
Сообщений: 2 111
Регистрация: 29-12-05
Пользователь №: 12 684

|
Цитата(Метценгерштейн @ Nov 15 2014, 12:52)  на самой нижней printf выдает ошибку при компиляции. Что не так ему? код под visual studio
все, разобрался, заработал код. Спасибо. да, код исправлен printf("%s", c); -> printf("%c", c); но непонятно, как вы можете найти вторую запятую, если выше ограничились только английскими буквами нижнего регистра if ((str[i] >= 97) & (str[i] <= 122))
|
|
|
|
|
Nov 15 2014, 16:08
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(Метценгерштейн @ Nov 15 2014, 12:52)  все, разобрался, заработал код. Спасибо. Вы меня извините, но так, как пишите вы, вообще писать нельзя. Волосы дыбом встают, когда глядишь на ваш код.  А то, что он заработал (т.е. его результат удовлетворяет вашим потребностям), делает ситуацию еще хуже - стимулирует вас и дальше писать в подобном духе. Из недостатков вашего кода самым вопиющим является использование значений неинициализированных переменных. Даже не пойму, отчего компилятор на вас за это не ругается - скорее всего, вы либо отключили варнинги, либо уже приучились не обращаеть на них внимания. В частности, значение переменной z1 не определено до тех пор, пока в тексте не встретится первая запятая, поскольку z1 получает присвоение только в операторе условия: if (str[i] == ',') z1 = i; // запомнили где запятая (начало слова), а до тех пор вообще непонятно, в какую память вы лезете, когда образуете от z1 индекс: str[z1 + 1 + f] Дальше. Системы поистка в цикле for так не пишутся, поскольку вы не отличаете экстра-выход из него по break, от естественного окончания цикла, когда он так ничего и не нашел. Поэтому вот это: char c = str[z1 + 1 + f]; - полнейшая чепуха, поскольку далеко не факт, что вторая запятая была найдена, а f отвечает ее позиции относительно первой запятой. А вот за такое сразу бейте себя в лоб, чтобы стало больно: if ((str[i] >= 97) & (str[i] <= 122)) Логические выражения комбинируют через операторы && или ||, а не через одиночные & или |. Только не пытайтесь мне доказывать, что это все равно, т.к. если вы привыкнете к такому стилю, то впереди вас ждут сильнейшие неприятности в виде ошибок, до причин которых вам никогда не докопаться. А пока примите на веру, что в логических выражениях операторы тоже должны быть логическими (за нечастыми исключениями). Что касается вашей задачи, разбить строку по запятым, то она решается тривиально с помощью стандартной функции strtok(). Посмотрите примеры с ее использованием и все поймете сами.
|
|
|
|
|
Nov 17 2014, 19:17
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(Метценгерштейн @ Nov 17 2014, 21:08)  давайте разбираться. переменная z1. Я ее объявляю типом int. Не хочу ее прямо там инициализировать. Почему нет? Инициализирую, когда мне это надо. Что здесь не так? Предположим, что первый байт в строке равен 100. Вы входите в цикл for (int i = 0; i < sizeof(str); i++) и условие if (str[i] == ',') z1 = i; // запомнили где запятая (начало слова) у вас, естественно, не выполняется, т.к. код 100 это не запятая, а следовательно, переменная z1 так и остается неинициализированной. Но на этом нулевой цикл по i не закончился, а продолжается дальше. Входим в условие if ((str[i] >= 97) & (str[i] <= 122)) и обнаруживаем, что оно верно, т.к. 100 где-то между 97 и 122. А потому входим во второй цикл for (int f = 0; f < 5; f++) где на каждом обороте требутся проверить условие if ((str[(z1 + 1 + f)]) == ',') // дошли до второй запятой с котором фигурует символ str[(z1 + 1 + f)]), доставаемый по вычисляемому индексу z1 + 1 + f А как его вычислять, если z1 до сих пор неинициализирована? Напоминаю, что мы всё еще находимся в состоянии, когда i==0, f==0, str[0]==100, а z1==неопределена, т.к. запятой еще не было. Потом цикл по f попрет дальше до 5, заставляя лазить в память str[(z1 + 1 + f)]), где z1 по-прежнему неинициализирована. А поскольку условие if ((str[(z1 + 1 + f)]) == ',') // дошли до второй запятой в запредельной памяти он едва ли найдет, то цикл f на каждом своем обороте будет распечатывать это: char c = str[(z1 + 1 + f)]; printf("%c", c); где переменная "c" копирует в себя значение из массива с больным индексом.
|
|
|
|
|
Nov 17 2014, 19:58
|
Профессионал
    
Группа: Свой
Сообщений: 1 357
Регистрация: 12-04-05
Из: Петербург
Пользователь №: 4 079

|
да, Вы правы. Упустил из виду что первый символ может быть сразу в диапазоне значений спасет ли ситуацию, если я сразу инициализирую z нулем? Не спасает, не печатает первое слово целиком. Код if ((str[i] >= 97) && (str[i] <= 122) || (str[i] >= 65) && (str[i] <= 90)) мне нужен диапазон латинских букв. так корректно && писать? Вообще, думал, что надо все же одну &, т.к. это обязательное условие, что диапазон от 97 до 122. зато если инициализировать z = -1; то тогда все нормально, первое слово печатает. если что- дальше значение переинициализируется и программа нормально отработает. Код void main (void) { setlocale(LC_ALL, "Russian"); int z1 =-1; char str[] = "прh,алf,б,авпле,gkпрб,alfer,онLфу,qwert.";
for (int i = 0; i < sizeof(str); i++) { if (str[i] == ',') { z1 = i; // запомнили где запятая (начало слова) }
if ((str[i] >= 97) && (str[i] <= 122) || (str[i] >= 65) && (str[i] <= 90)) { for (int f = 0; f < 6; f++) { if ( ((str[(z1 + 1 + f)]) == ',') || ((str[(z1 + 1 + f)]) == '.') ) // дошли до второй запятой или точки { i = z1 + f; printf("\n"); break; } char c = str[(z1 + 1 + f)]; // печатает символы по одному, пока не встретит запятую printf("%c", c); } } } system("pause>nul"); } давайте тогда сразу уже по критике. Что еще глаз режет? Данный код полностью рабочий. Задача- даны слова через запятую. После последнего слова- точка. слова до 5 букв. Вывести только те слова, где есть латинские буквы.
|
|
|
|
|
Nov 17 2014, 21:38
|

Гуру
     
Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237

|
Цитата(Метценгерштейн @ Nov 17 2014, 22:58)  спасет ли ситуацию, если я сразу инициализирую z нулем? Не спасет, т.к. запятая вполне может оказаться в самом начале строки (str[0]), а потому индекс z1==0 для запятой вполне легален. Цитата(Метценгерштейн @ Nov 17 2014, 22:58)  if ((str[i] >= 97) && (str[i] <= 122) || (str[i] >= 65) && (str[i] <= 90)) мне нужен диапазон латинских букв. так корректно && писать? Вообще, думал, что надо все же одну &, т.к. это обязательное условие, что диапазон от 97 до 122. Корректно так: if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') где оператор || соединяет два логических выражения, заключенных в скобки (лишние скобки я удалила, чтобы не мешали видеть логику). Как я вижу, вы по-прежнему не понимаете разницы между операциями & и &&, а так же между | и ||, а потому я вынуждена продолжить объяснения. Бинарные операторы & и | работают с ЦЕЛЫМИ ЧИСЛАМИ, и в результате своей операции тоже дают ЦЕЛОЕ ЧИСЛО. В этом смысле они родные братья арифметических операторов + - * / и по существу от них ничем не отличаются. Тогда как логичеcкие операторы && и || работают с БУЛЕВЫМИ величинами типа TRUE и FALSE. И результат их операции тоже БУЛЕВАЯ величина. Переход от числовых величин к булевым осуществляют обычно операторы сравнения < <= > >= == !=. Именно они работают с числами, а в результате дают буля. После того, как вы что-то сравнили, у вас все числа и литеры превратились в булей, а потому дальше работать с булями возможно лишь с помощью && и ||,а про остальную арифметику забыть. Язык C зачастую позволяет смешение типов, порой даже не выдавая на этот счет предупреждения, однако НЕ НАДО (!!!) без особой необходимости этим злоупотреблять. Этим вы не компилятору сделаете хуже, а самому себе! А если C++ будете осваивать, то там со смешением типов и вовсе строго. Поэтому чем раньше приучаться к дисциплине, тем лучше. А по началу предлагаю вам писать в качестве комментария обоснование причины, когда вы смешиваете разные типы, подсовывая операторам плохоперевариваемые продукты. Вы ведь не делите букву на букву, когда понимаете, что в этих байтах лежат буквы, а не цифры? А, значит, разницу должны понимать, несмотря на то, что компилятору разделить две буквы друг на друга не составит труда. Это потому что язык С такой покладистый и малоругачий. Например, почему я заменила выражение str[i] >= 97 на str[i] >= 'a' хотя это в кодах одно и тоже? А потому что в первом случае в комментариях должно быть написано: str[i] >= 97 // Я, Метценгерштейн, старый м...к, до сих пор не понимаю разницы между буквами и цифрами  Между тем, второй вариант был бы совершенно правильным, если бы по смыслу массив str был бы набит числами, скажем, от 8-разрядного АЦП. Вот и в том старом варианте резало глаз, когда вы скармливали числовому оператору & два булевских аргумента. Я сразу же его пожалела, а вы не заметили, что ему скормили. Бывают случаи, когда действительно есть необходимость подвергнуть букву числовой операции. Например, чтобы превратить большую литеру в маленькую и обратно. Но это тот самый уважительный случай, когда возникла НЕОБХОДИМОСТЬ! А вот заменять литеру 'z' на число 122 у вас такой необходимости не было, а потому и должны писать в комментарии оправдание своим действиям. Цитата(Метценгерштейн @ Nov 17 2014, 22:58)  давайте тогда сразу уже по критике. Что еще глаз режет? Данный код полностью рабочий. Ваш код режет глаз тем, что с фиговым z1 вообще на надо входить в цикл f! Лучше было бы написать проще, оно и понятнее: Код int z1 = 0; // начало первого слова
for (int i = 0; i < sizeof(str); i++) { if (str[i] == ',' || str[i] == '.') // если нашли запятую или точку, то { for (int f = z1; f < i; f++) printf("%c", str[f]); // печатаем слово до запятой или точки printf("\n"); z1 = i+1; // запоминаем начало следующего слова } } А если требуется фильтрация алфавитных литер от прочих, то вставляете выражение if ((str[f] >= 'a' && str[f] <= 'z') || (str[f] >= 'A' && str[f] <= 'Z') в цикл f перед печатью.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|