2014 dxdy logo

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

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




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


26/04/10
116
доброе утро! я решаю задачу: есть строка, в которой слова разделены запятыми, нужно вывести все слова, в которых есть двойные буквы.
текст программы:
Код:
#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 
Заслуженный участник


08/04/08
8504
А что такое
Код:
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 


26/04/10
116
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 
Аватара пользователя


01/04/10
910
Начал переделывать Ваш код. В итоге получилось следующее :-)

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

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

код: (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 


26/04/10
116
creative в сообщении #339505 писал(а):
Начал переделывать Ваш код. В итоге получилось следующее :-)

(Оффтоп)

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

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

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


01/04/10
910
ADRenaLIN

(Оффтоп)

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


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

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


26/04/10
116
creative в сообщении #339519 писал(а):
Для новичка код подходит. Изучите программу запустив её в отладчике.

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

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


01/04/10
910
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 
Заслуженный участник


26/07/09
1559
Алматы
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 
Аватара пользователя


01/04/10
910
Circiter

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

 Профиль  
                  
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение21.07.2010, 00:27 
Заслуженный участник


26/07/09
1559
Алматы
2creative
Цитата:
в чём преимущество Вашего кода кроме использования библиотечной функции?

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

(Оффтоп)

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

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


01/04/10
910
Circiter

(Оффтоп)

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

 Профиль  
                  
 
 Re: изучаю самостоятельно Си (помогите исправить прогу)
Сообщение23.07.2010, 03:11 


13/09/09
72
Цитата:
http://www.youtube.com/watch?v=mnXkiAKbUPg
Весело. :D
Нет ли еще каких нибудь видео в таком духе?

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 13 ] 

Модераторы: Toucan, maxal, PAV, Karan, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group