LINUX.ORG.RU

Наноконкурс по Си :)

 , ,


4

2

Вдохновленный подобным запилю свой маленький топик :) В 2010, читая Седжвика, увидел такую задачу:

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

Проще некуда, ведь правда?

Для ее решения был накрапан такой быдлокод

#include <iostream>
#include <unistd.h>
#include <string.h>

using namespace std;

int main(int argc, char* argv[])
{ const int N = 255;
  const unsigned int sz = 26;
  static int l = 0;
  const char alf[sz]={'a','b','c','d','e','f','g','h','i','j','k','l','m',
						 'n','o','p','q','r','s','t','u','w','x','y','z'};
  int index[sz];
  char str[N];
   for (int i = 0; i < sz;i++)
   {index[i] = 0;
   }
   cin >> str;
   cout <<'\n';
   for ( unsigned int j = 0; j < (strlen(str));j++)
   {   if(str[j] < 0x61)
	   str[j] = _tolower(str[j]);
	 for (int k = 0; k < sz;k++){
		 if (str[j] == alf[k]) index[k]++;}  
   }
    cout <<'\t';
	for(int l = 0; l < sz;l++)
	  if (index[l]) { 
		  cout << alf[l] <<" ";
		  cout << index[l] <<'\n' <<'\t';
	  } 
	sleep(7);
   return 0;
}
Тут правда табуляции корежать линуксовый терминал, немного, но тогда дело было под оффтопом. Из того, что хотелось бы улучшить, например, чтобы программа выводила еще и позицию заданного символа от начала строки.

Короче, принимаются ваши красивые решения господа, а также коменты Царя, про мою тотальную АНскильность, хроническое НИасиляторство и даунизм. You are welcome!

★★★★★

Последнее исправление: beastie (всего исправлений: 3)

Ответ на: комментарий от Eddy_Em

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

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)

Да и еще Царь меня может попинать за использование некошерного cout в сишечке и лишний хидер :D

Twissel ★★★★★
() автор топика
Ответ на: комментарий от val-amart

Дык, я про это и написал. Просто тогда пользовался ими по привычке от индуса Шилдта, молодо, зелено было :)

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
cat 1.c 
#include <stdio.h>
#include <ctype.h>

void proc_hist(int *H, char *S){
	if(!S || !*S) return;
	do{
		if(isalpha(*S))
			H[tolower(*S)-'a']++;
	}while(*++S);
}

int main(int argc, char **argv){
	int i;
	int hist[26] = {0};
	if(argc == 1){
		printf("usage: %s text", argv[0]);
		return 1;
	}
	for(i = 1; i < argc; i++){
		proc_hist(hist, argv[i]);
	}
	for(i = 0; i < 26; i++)
		if(hist[i])
			printf("letter %c meets %d times\n", 'a'+i, hist[i]);
	return 0;
}

gcc -Wall -Werror 1.c -o str_histogram

./str_histogram Let\'s get the facts
letter a meets 1 times
letter c meets 1 times
letter e meets 3 times
letter f meets 1 times
letter g meets 1 times
letter h meets 1 times
letter l meets 1 times
letter s meets 2 times
letter t meets 4 times

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Принимается. Ща вникну. Спасибо.

Twissel ★★★★★
() автор топика
Ответ на: комментарий от val-amart

И вправду работает. Поскольку де-факто юникс вырос на Си принимается

P.S.Вы неплохо справляетесь с ролью Царя, хотя по стилю видно, что Вам за 30. Угадал?

Twissel ★★★★★
() автор топика
#include <stdio.h>
#include <ctype.h>
char tbl[256]={0};
int
main(int c,char* a[])
{
	if(c<2)return 0;
	char *b=a[1];
	while(*b){
		tbl[tolower(*b++)]++;
	}
	for(c='a';c<='z';c++){
		if(tbl[c]){
			printf("%c\t%4d\n",c,tbl[c]);
		}
	}
	return 0;
}
qulinxao ★★☆
()

fix

cat 1.c 
#include <stdio.h>
#include <ctype.h>

void proc_hist(int *H, char *S){
	if(!S || !*S) return;
	do{
		if(isalpha(*S))
			H[tolower(*S)-'a']++;
	}while(*++S);
}

void print_hist(int i, int imax){
	if(imax > 80)
		i = i*80 / imax;
	while(i--){
		printf("*");
	}
	printf("\n");
}

int main(int argc, char **argv){
	int i, lmax = 0;
	int hist[26] = {0};
	if(argc == 1){
		printf("usage: %s text", argv[0]);
		return 1;
	}
	for(i = 1; i < argc; i++){
		proc_hist(hist, argv[i]);
	}
	for(i = 0; i < 26; i++)
		if(hist[i] > lmax) lmax = hist[i];
	for(i = 0; i < 26; i++)
		if(hist[i]){
			printf("%c: ", 'a'+i);
			print_hist(hist[i], lmax);
		}
	return 0;
}

gcc -Wall -Werror 1.c -o str_histogram

./str_histogram Let\'s get the facts, I know that this will work. Now let\'s just count a number of letters in this small text. You can see, it doesn\'t count non-letter symbols. Also it need protection of apostrophe, quotation marks and some other symbols. Shame to me! But to count cyrillic letters this will be muchmore complex. 
a: ***********
b: *****
c: **********
d: ***
e: **************************
f: ***
g: *
h: *********
i: *************
j: *
k: ***
l: *****************
m: ***********
n: ***************
o: **************************
p: ****
q: *
r: ***********
s: *********************
t: **********************************
u: *********
w: *****
x: **
y: ****
Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от qulinxao

Хорошо, Вам «плюс» за компактность. Хотя, лично для меня, у Эдика вариант читабельней. Да и версия 2.0 уже релизнулась :D

Twissel ★★★★★
() автор топика

okay

serge@blackblade:~$ cat char_bar_chart.c 
#include <stdio.h>
#include <stdlib.h>

#include <strings.h>

#define RESULT_SIZE 256

int main(int argc, char **argv) {
  int result[RESULT_SIZE];

  char *current_char;

  int current_position;
  int current_result;

  bzero((void *) result, sizeof(result));

  if (argc != 2) {
    printf("usage:\n\t%s \"some string\"\n", argv[0]);

    return 1;
  }

  for (current_char = argv[1]; *current_char; current_char++) {
    result[*current_char]++;
  }

  printf("\nstring: %s\n", argv[1]);
  printf("char\tcount\n");

  for (current_position = 0; current_position < RESULT_SIZE; current_position++) {
    if ((current_result = result[current_position]) > 0) {
      printf("%c\t%i\n", current_position, current_result);
    }
  }

  return 0;
}

serge@blackblade:~$ gcc -o char_bar_chart char_bar_chart.c
serge@blackblade:~$ ./char_bar_chart "some string"

string: some string
char    count
        1
e       1
g       1
i       1
m       1
n       1
o       1
r       1
s       2
t       1

или таки надо гистограмму а не таблицу?

exception13 ★★★★★
()
Последнее исправление: exception13 (всего исправлений: 1)
Ответ на: комментарий от Twissel

де-факто юникс вырос на Си

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

т.е. си можно и на голую машину компилировать , но изначальный си ориентирован на юникс среду.

си появился после юникса , и вторичен к юниксу(и тому образу мышления Патриархов который и создал unIX а затем planIX)

qulinxao ★★☆
()
Ответ на: комментарий от Twissel

его вывод (первый вариант) многословен :)

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

очевидный код очевиден.

вариант с fold -w1 рулит и педалит.

qulinxao ★★☆
()
Ответ на: комментарий от Eddy_Em

ну с как и sh языки имплементации

для | не важно на чём реализованы команды которые склеивают.

qulinxao ★★☆
()
Ответ на: комментарий от qulinxao

хрюникод ☺

А еще ты "забудешь" заглавные буквы. Ну и зачем считать все символы, если надо только буквы?

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

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

val-amart ★★★★★
()
Ответ на: комментарий от exception13

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

Twissel ★★★★★
() автор топика
Ответ на: комментарий от val-amart

Вот я и говорю, что параллельно они развивались. С был создан как "кроссплатформенный ассемблер". А потом как-то прижилось, всем понравилось. В конце-концов на С и перешли со всяких страшных фортранов и прочих фортов.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от anonymous

нет :(

вместо fold можно использовать такой трюк: «grep -o .» — он работает с юникодом.

val-amart ★★★★★
()

Прошлый конкурс пропустил, так хоть в этом отмечусь.

В тред не смотрел, для спортивного интересу.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>

static uint count[SCHAR_MAX-' '];

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

    if(argc < 2)
    {
        printf("Usage: %s <somestring>\n", argv[0]);
        return 1;
    }

    char *str = argv[1];

    for(;i<strlen(str);i++)
    {
        ++count[*(str+i)-' '];
    }

    printf("_______\n");
    for(i=0;i<sizeof(count)/sizeof(uint);i++)
    {
        if(count[i] > 0)
        {
            printf("|%c |%.2d|\n", i+' ', count[i]);
        }
    }

    printf("-------\n");

    return 0;
}
Reinar
()
Ответ на: не благодари от lovesan

О, распечатать же еще надо. Ну тогда так:

(format t "~{~{~a ~a~}~%~}"
        (reduce (lambda (x y &aux (z (assoc y x)))
                  (or (and z (incf (cadr z)) x)
                      (cons (list y 1) x)))
                (read-line)
                :initial-value '()))

lovesan ★★
()
Ответ на: комментарий от Twissel
#include <stdio.h>
#include <ctype.h>
char tbl[256]={0};
int  pos[256]={0};
int
main(int c,char* a[])
{
	if(c<2)return 0;
	char *b=a[1],*s=b-1,t;
	while(*b){
		t=tolower(*b);
		tbl[t]++;
		pos[t]+=(!pos[t])*(b-s);
		b++;
	}
	for(c='a';c<='z';c++){
		if(tbl[c]){
			printf("%c\t%4d\n",c,tbl[c]);
		}
	}
	scanf("%c",&t);t=tolower(t);
	if(pos[t]){
		printf("%d\n",pos[t]-1);
	}else{
		//cose we in unix we not output silly empty info
	};
	return 0;
}
qulinxao ★★☆
()
Ответ на: комментарий от Eddy_Em

Позор. Три цикла, там где нужно два (и то быдлокод).

Зачем гоняешь байты? Всё равно массив завёл. А то, что ты его передаёшь аргументом не делает его неглобальным.

ziemin ★★
()
Ответ на: комментарий от Twissel
cat 2.c 
#include <stdio.h>
#include <ctype.h>

void proc_hist(int *H, char *S){
	if(!S || !*S) return;
	do{
		if(isalpha(*S))
			H[tolower(*S)-'a']++;
	}while(*++S);
}

int main(int argc, char **argv){
	int i;
	char *ptr, s;
	int hist[26] = {0};
	if(argc != 3){
		printf("usage: %s \"text\" letter", argv[0]);
		return 1;
	}
	proc_hist(hist, argv[1]);
	for(i = 0; i < 26; i++)
		if(hist[i])
			printf("%c:\t%d\n", 'a'+i, hist[i]);
	s = *argv[2];
	printf("Позиции символа %c:\n", s);
	ptr = argv[1];
	i = 0;
	do{
		if(*ptr == s) printf("%d ", i);
		i++;
	}while(*++ptr);
	printf("\n");
	return 0;
}

gcc -Wall -Werror 2.c -o str_histogram

./str_histogram "Let\'s get the facts, I know that this will work. Now let\'s just count a number of letters in this small text. You can see, it doesn\'t count non-letter symbols. Also it need protection of apostrophe, quotation marks and some other symbols. Shame to me! But to count cyrillic letters this will be muchmore complex." c
a:	11
b:	5
c:	10
d:	3
e:	26
f:	3
g:	1
h:	9
i:	13
j:	1
k:	3
l:	17
m:	11
n:	15
o:	26
p:	4
q:	1
r:	11
s:	21
t:	34
u:	9
w:	5
x:	2
y:	4
Позиции символа c:
17 66 116 137 181 262 268 275 300 307 
Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Reinar

Вам большой и жирный плюс за использование строковых функций, просто потому,что эта маленькая задачка находилась в главе АТД раздел «Строки». Спасибо :)

Twissel ★★★★★
() автор топика
Последнее исправление: Twissel (всего исправлений: 1)
#include <stdio.h>
#include <ctype.h>

int main()
{
    int c, total = 0, table[26] = {0};
    const char *hist = "*********************";

    while ((c = getchar()) != EOF)
        if(isalpha(c)) total++,
            table[tolower(c) - 'a']++;
    
    for (c = 0; c < 26; c++) if (table[c])
        printf("%c: %5d %.*s\n", 'a' + c, table[c],
            (int) 20.0 * table[c] / total + 1, hist);
}
mix_mix ★★★★★
()
Последнее исправление: mix_mix (всего исправлений: 1)
Ответ на: комментарий от qnikst

Хм, простите. Ссылки не будет. Просто маленькая разминка. Написано же «наноконкурс». Весь код в студию!

Twissel ★★★★★
() автор топика
Ответ на: комментарий от Twissel

А где return 0 ?! И вообще, Ваш вариант радует меня зависшей консолькой ;)

У меня clang давно перестал ругаться на такое, можете добавить, если хочется. Висит так как ждёт данные: cat file.txt | ./a.out

mix_mix ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.