2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 07:46 
доброе утро! я решаю задачу: есть строка, в которой слова разделены запятыми, нужно вывести все слова, в которых есть двойные буквы.
текст программы:
Код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char s[]="class,home,summer,day";
    puts(s);
    char sl[10]="";
    char c[]=",";
    int i;
    for (i=0;i<=strlen(s)-1;i++)
    {
         if (s[i] != c) sl = sl + s[i];
            else
            {
                int j=0;
                while (sl[j-1])
                {
                    if (sl[j]==sl[j+1]) puts(sl);
                    j++;
                };
                sl = "";[/b]
            };
    };
    return 0;
}


ЗЫ: на Паскале подобная программа работает, а в Си ругается...
Ругается, в частности, на строки где идет присваивание для переменной sl. Подскажите в чем тут подвох...

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 07:53 
А что такое
Код:
while(sl[j-1])

?
И как вообще работает код
Код:
int j=0;
while(sl[j-1])

sl[-1] определен? :roll:

-- Пт июл 16, 2010 08:56:58 --

Кусок кода:
Код:
if (sl[j]==sl[j+1]) puts(sl);
                    j++;

А если в слове будет 2 пары совпадающих букв? 2 раза напишет?

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 08:33 
Sonic86 в сообщении #339472 писал(а):
Кусок кода:
Код:
if (sl[j]==sl[j+1]) puts(sl);
                    j++;

А если в слове будет 2 пары совпадающих букв? 2 раза напишет?

не придерайтесь к мелочам :) пусть два раза выведет, это можно потом учесть...

-- Пт июл 16, 2010 09:37:07 --

Sonic86 в сообщении #339472 писал(а):
И как вообще работает код
Код:
int j=0;
while(sl[j-1])

sl[-1] определен? :roll:

Код:
int j=0;
while(sl[j])

вот так...
вообще в литературе нашла, что берет символ из строки, если он не конец строки, то идем в цикл

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 13:24 
Аватара пользователя
Начал переделывать Ваш код. В итоге получилось следующее :-)

Работает и с пробелами и с запятыми в качестве разделителей. Принимает аргумент из командной строки.

Разделяйте код на функции и связывайте данные в структуры, если они улучшают ясность и связаны по смыслу и используйте стандарт оформления кода (доп. главы раз, два), тогда Ваш код будет выглядеть лучше и Вы сами сможете найти ошибки в нём не прикладывая больших усилий.

код: (print_words.c) [ скачать ] [ спрятать ]
Используется синтаксис C
[highlight]

#include <stdio.h>

const char cm = ',';

inline char *next_word(char *s);
inline void put_double_ch_word(char *s);

int main(int argc, char *argv[])
{
    int i;
    char *s;

    if (argc == 1) return 0;

    i = 1;

    while (i < argc) {
        s = argv[i];

        if (s[0] == cm) s = next_word(s);

        while (s) {
            put_double_ch_word(s);
            s = next_word(s);
        }

    i++;
    }

    return 0;
}

inline char *next_word(char *s)
{
    size_t i = 0;

    while ( s[i] ) {
        if (s[i] == cm && s[i + 1] != cm && s[i + 1])
        {
            return &s[i + 1];
        }

        i++;
    }

    return NULL;
}

inline void put_double_ch_word(char *s)
{
    size_t i = 0;
    char flag = 0;

    while ( s[i] ) {
        if (s[i + 1] == cm) break;

        if (s[i] == s[i + 1]) {
           flag = 1;
           break;
        }

        i++;
    }

    if (!flag) return;

    i = 0;

    while ( s[i] ) {
        if (s[i] == cm) break;
        putchar(s[i]);

        i++;
    }

    putchar('\n');
}

[/highlight]

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 14:55 
creative в сообщении #339505 писал(а):
Начал переделывать Ваш код. В итоге получилось следующее :-)

(Оффтоп)

вы или шутите так или у вас жара 35С...

очень доступно для новичка, я скажу :shock:

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 15:07 
Аватара пользователя
ADRenaLIN

(Оффтоп)

Я не подразумевал сарказм.


Для новичка код подходит. Изучите программу запустив её в отладчике.

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 15:12 
creative в сообщении #339519 писал(а):
Для новичка код подходит. Изучите программу запустив её в отладчике.

я как программист (программирую на языке сильно отличающемся от Си) и педагог (математик-информатик) говорю, что для новичка код сложен...
я Си изучаю неделю с минимумом литературы (можно сказать, что совсем без нее)
вот с этим char *s; я пока вообще не дружу, поэтому мне вдвойне сложнее понять программу

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение16.07.2010, 15:54 
Аватара пользователя
ADRenaLIN в сообщении #339521 писал(а):
вот с этим char *s; я пока вообще не дружу, поэтому мне вдвойне сложнее понять программу


Это объявление указателя. Вкратце суть заключается в следующем:

  1.     type a; 
  2.     type *p; 
  3.  
  4.     a = val1; 
  5.     p = &a; 
  6.  
  7.     *p = val2; 


Где, type это тип, а a и p это переменные. Значение a хранится по адресу &a (& - операция взятия адреса). Значение имеет тип type. p это переменная-указатель, то есть её значением является адрес значения имеющий тип type. По адресу &p хранится значение, которое является адресом (тафтология, но это так).
В строке 4 переменной a присваивается значение val1.
В строке 5 переменной p присваивается значение, которое есть адрес переменной a.
В строке 7 используется операция разыменовывания * (в объявлении символ * не является операцией разыменовывания). Данная операция означет следующее:

Взять значение переменной p, которая является адресом, далее считать или перезаписать значение ячеек по данному адресу памяти.

В данном случае *p = 3 записывает значение val2 по адресу &a, то есть теперь переменная a содержит val2.

Частный случай:

Используется синтаксис C
[highlight]
    char *s = "abc"; //выделена память по определённому адресу для четырёх ячеек (abc и нулевой байт)
    putchar(*s); //напечатать: a
    putchar(s[0]); //напечатать: a - обращение по индексу s[i] тоже самое, что и *(s + i)
    s++;
    putchar(*s); //напечатать: b
[/highlight]
 


Дополнение:

Используется синтаксис C
[highlight]
    char a[10]; //выделить массив содержащий десять символов
    char *vs[10]; //выделить массив содержащий десять указателей на символы
[/highlight]
 


Четыре года назад мне понравилось следующее видео про указатели:

http://www.youtube.com/watch?v=mnXkiAKbUPg

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение20.07.2010, 04:46 
2ADRenaLIN
Для извлечения слов из строки можно воспользоваться C'шным "парсером" strtok(...) из string.h.

Это очень просто:
Используется синтаксис C
    char *Word=strtok(Input, ",");
    do printf("%s\n", Word); while(Word=strtok(NULL, ","));
 


К сожалению, этот глупый подход делит строку на строки также грубо как и код creative'a (хотя его код правильно отфильтровывает слова с удвоенными буквами).

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

Но я все-таки приведу пример решения вашей задачки с применением именно такого подхода; протестируйте его (теперь распознаются слова с удвоенными буквами):
код: [ скачать ] [ спрятать ]
Используется синтаксис C
#include <stdio.h>
#include <string.h>

/* Warning! Source data will be damaged. */
void Extract(char *Input)
{
    char *Word, *Extracted, Symbol;

    /* Extract first word. */
    if(Extracted=Word=strtok(Input, ", "))
        do
            /* Scan current word. */
            while(Symbol=*Word)
                /* Find "duplet". */
                if(Symbol==*++Word)
                {
                    /* Print current word and
                       continue the extraction process. */

                    printf("%s\n", Extracted);
                    break;
                }
        /* Extract next word. */
        while(Extracted=Word=strtok(NULL, ", "));
}
 


Что же касается вашего неработающего кода... Проблема вашего кода не только в том, что вы напутали с алгоритмом и индексами, но и в том, что вы перенесли нормальные для мира pascal'а идиомы на более низкоуровневый язык, коим является C.

Вот например, взглянем на конструкцию sl = sl + s[i]. Вы хотели добиться конкатенации sl и символа s[i]. Это подразумевает по крайней мере автоматическое перераспределение памяти для размещения в ней увеличивающейся строки. Но ничего такого в C и близко нет! И даже понятия "строка" в нем тоже нет! Строки это всего-лишь указатели на соответствующий кусок памяти, т.е. всего-лишь число... И с этими числами можно выполнять арифметические операции. Например если s -- строка, то s+1 будет той-же строкой, но без первого символа (прибавив единицу мы сместились на один символ "вправо").

Так в вашем случае вы должны просто запоминать "позицию" искомого слова и затем выводить соответствующий фрагмент исходной строки. Например по указателю на начало слова и длине слова. Именно поэтому ранее упоминавшаяся функция strtok(...) портит строку -- она просто вставляет после выделенного слова нулевой символ-ограничитель на который можно ориентироваться при извлечении слова.

Кстати, коль скоро в C используются null-terminated строки, то и про функцию strlen(...) лучше вспоминать лишь в крайнем случае (для определения длины строки эта функция сканирует всю строку, ища нулевой ограничитель; в то время как в pascal-строках длина хранится вместе со строкой).

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение20.07.2010, 11:13 
Аватара пользователя
Circiter

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

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение21.07.2010, 00:27 
2creative
Цитата:
в чём преимущество Вашего кода кроме использования библиотечной функции?

Только в использовании библиотечной функции. :)

(Оффтоп)

Зачем вы используете [highlight] при оформлении фрагментов своего кода? :)

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение21.07.2010, 12:00 
Аватара пользователя
Circiter

(Оффтоп)

Что-то у меня код упорно не подсвечивался, хотя сейчас попробовал, вроде нормально тег [syntax] работает.

 
 
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение23.07.2010, 03:11 
Цитата:
http://www.youtube.com/watch?v=mnXkiAKbUPg
Весело. :D
Нет ли еще каких нибудь видео в таком духе?

 
 
 [ Сообщений: 13 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group