Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: printf
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Метценгерштейн
что-то не получается.
есть массив char, содержит 5 символов. никакого завершающего нуля нет.
как мне его напечатать?
Xenia
Цитата(Метценгерштейн @ Nov 15 2014, 02:30) *
есть массив char, содержит 5 символов. никакого завершающего нуля нет.
как мне его напечатать?


Как строку, но с ограничителем в формате:

char array[5] = {'a', 'b', 'c', 'd', 'e'}
printf( "%5.5s\n", array);

такой формат запретит печатать строку дальше 5-го символа, а потому будет не важно, есть в конце нуль или нет.
Метценгерштейн
а если у меня массив символов не всегда 5, а может 3 или 4 быть.
То как?
просто печать массива не вывести никак?
если никак, то могу '\0' добавить концом

с концом строки просто
printf("%s", temp);
Xenia
Цитата(Метценгерштейн @ 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 байт вместе с мусором?
Метценгерштейн
Код
#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

все, разобрался, заработал код.
Спасибо.
ViKo
Цитата(Метценгерштейн @ Nov 15 2014, 02:51) *
если никак, то могу '\0' добавить концом

добавьте, что вам мешает?
l1l1l1
Цитата(Метценгерштейн @ Nov 15 2014, 12:52) *
на самой нижней printf выдает ошибку при компиляции. Что не так ему? код под visual studio

все, разобрался, заработал код.
Спасибо.

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


Вы меня извините, но так, как пишите вы, вообще писать нельзя. Волосы дыбом встают, когда глядишь на ваш код. sm.gif А то, что он заработал (т.е. его результат удовлетворяет вашим потребностям), делает ситуацию еще хуже - стимулирует вас и дальше писать в подобном духе.

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

В частности, значение переменной 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(). Посмотрите примеры с ее использованием и все поймете сами.
Метценгерштейн
давайте разбираться.
переменная z1.
Я ее объявляю типом int. Не хочу ее прямо там инициализировать. Почему нет? Инициализирую, когда мне это надо. Что здесь не так?

по второму замечанию - условие задачи- слова разделенные запятыми, но слово не больше 5 букв. Так что, если нет второй запятой, то из цикла выйдет и так.

за && - спасибо. Учту. А можно подробней разницу? Т.к. на практике работает и так и так.

библиотечной ф-ей по условию пользоваться нельзя было. Пришлось городить.

В целом, за критику спасибо)
doom13
Цитата(Метценгерштейн @ Nov 17 2014, 21:08) *
за && - спасибо. Учту. А можно подробней разницу? Т.к. на практике работает и так и так.

(А && B ) - логическое И (применяется в условных опереторах), выполнится если A - истина и В - истина.
(A & B ) - побитовое И, если важен результат A и B, условный оператор выполнится, если (A & B ) = истина.
Xenia
Цитата(Метценгерштейн @ 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" копирует в себя значение из массива с больным индексом.
Метценгерштейн
да, Вы правы.
Упустил из виду что первый символ может быть сразу в диапазоне значений

спасет ли ситуацию, если я сразу инициализирую 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 букв. Вывести только те слова, где есть латинские буквы.
Xenia
Цитата(Метценгерштейн @ 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 // Я, Метценгерштейн, старый м...к, до сих пор не понимаю разницы между буквами и цифрами sm.gif
Между тем, второй вариант был бы совершенно правильным, если бы по смыслу массив 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 перед печатью.
Метценгерштейн
в целом да, согласен. Насчет 97 и 'a'- давайте спорить.
Где-то я не использовал цифры из юникода, где-то использовал ',' а не юникод.
Оператор '' у нас чем занимается? Возвращает цифровое значение элемента.
Не наглядно, согласен. В дальнейшем я и использовал не цифру, а ','
Xenia
Цитата(Метценгерштейн @ Nov 18 2014, 12:19) *
в целом да, согласен. Насчет 97 и 'a'- давайте спорить.
Где-то я не использовал цифры из юникода, где-то использовал ',' а не юникод.


Так вы еще и Юникод с ANSI путаете?
Пишите, как хотите! Вы спросили, чем мне ваша манера програмирования глаз режет - я ответила, а бодаться с сами у меня настроения нет. Тем более что я и так уделила вашему коду гораздо больше внимания, что тот заслуживает.
alx.bilous
Цитата(Xenia @ Nov 15 2014, 02:37) *
Как строку, но с ограничителем в формате:

char array[5] = {'a', 'b', 'c', 'd', 'e'}
printf( "%5.5s\n", array);

такой формат запретит печатать строку дальше 5-го символа, а потому будет не важно, есть в конце нуль или нет.


Цитата
The width and precision formatting parameters may be omitted, or they can be a fixed number embedded in the format string, or passed as another function argument when indicated by an asterisk "*" in the format string. For example printf("%*d", 5, 10) will result in " 10" being printed, with a total width of 5 characters, and printf("%.*s", 3, "abcdef") will result in "abc" being printed.


Легко заметить, что нету каких либо требований, что бы аргумент размера был константой
Xenia
Цитата(alx.bilous @ Nov 24 2014, 14:09) *
printf("%.*s", 3, "abcdef")
Легко заметить, что нету каких либо требований, что бы аргумент размера был константой


Далеко не все компиляторы понимают такой формат. Компиляторы для микроконтроллеров обычно не понимают.
alx.bilous
гцц понимает, keil понимает, аврка понимает, iar вроде тоже как. Значит практически все компиляторы понимают?
И вообще, "*" стандарт явно определяет.

Ну и то что маргинальные компиляторы не могут в этот формат, никак не означает что нельзя использовать эту функцию
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.