LINUX.ORG.RU

Посчитать количетсво определенного слова в файле

 


0

2
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

int main()
{   FILE *myfile;

        int k=0;
        char name[100];
        char word[20];

        printf("Enter name of file: ");
        scanf("%s", name);
        if ((myfile = fopen(name, "r")) == NULL)
        {
         puts ("File is not found");
         exit(0);
        }


        printf("Enter word: ");
        scanf("%s", word);

       return 0;
    }


Помогите дописать код
нужно посчитать количество слова, которое записано в переменной «word», в файле «name»
например ввели слово «dog»
посчитать сколько раз оно повторяеться в файле «new»

Спасибо за внимание и советы!


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

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

в том, что я больше половины дня уже ищу инфу как это сделать и из-за тупости, или из-за неопытности, или всё вместе, я не могу сделать ничего толкового

может, подскажите хотя бы функцию, которой пользоваться?!

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

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

Если же я не прав, то распиши-ка тут, своими словами, как по-твоему должна действовать программа, чтобы посчитать слово в файле. Какие и в какой последовательности действия она должна выполнять? Представь, что ты и есть эта программа. И вот тебе надо посчитать. Что ты будешь делать для этого?

anonymous
()
Читаешь файл посимвольно fgetc();
Встретил пробел начинаешь заносить следующие за ним символы в переменную tmp.
Встретил ещё пробел сравниваешь значение этой переменной с переменной word strcmp(); если совпало делаешь k++; если нет обнуляешь tmp и начинаешь всё заново продолжая посимвольно читать текст.

Дошёл до EOF делаешь print("%d",k);

Всё

Deleted
()

Сначала придумай алгоритм короче, на бумажке чтоли нарисуй типа а как бы я это сделал сам без программы? Типа у меня есть набор символов и есть наборы других символов как бы я при ограничениях это сделал? Ну например у тебя есть 4 кубика со словом «лось» и куча других кубиков где есть слова «лось» и ещё есть 4 пустых кубика в которые можно положить только 4 буквы и сравнить со словом «лось» вот как бы ты выстроил последовательность сравния имея только вот эти кубики? Вот это и называется алгоритм придумай его а потом уже реализуй его в коде. И да ты же можешь ещё замеить что у тебя 4 кубика значит что? значит слова менее и более 4 кубиков ты можешь смело пропускать, а как пропускать ты их можешь? Правильно зная что между словами есть разделитель в виде пробела или иного символа. Как будешь знать алгоритм действия уже ищи/гугли/книги смотри как например прочитать символ, как добавить символ в массив как очистить массив как сравнить массивы и прочее тоесть элементарные вещи из который ты сложишь свой алгоритм

Deleted
()
Ответ на: комментарий от bormant

Может у него вообще нет разделителей там тогда просто сравнивать при чтении каждого нового символа делая смещение в пременной tmp и всё

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

спасибо вам за вышепредставленые советы над этим надо подуммать

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

тоесть, программа будет читать только строку, а если будет абзац, то она будет считать это концом файла?

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

Встретил пробел начинаешь заносить следующие за ним символы в переменную tmp

Это не оптимально. Оптимально сразу искать слово как подстроку в прочитанном буфере. Если это слово начинается с начала буфера, то проверяем символ только после слова на пробельный, если в конце буфера - перед словом на пробельный иначе - оба вокруг.

Боюсь только, что ТС указатели вряд ли осилит...

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

Ты о чём? Есть файл у него есть EOF всё. Всё что в нём просто поток символов по указателю FILE *

Deleted
()
Ответ на: комментарий от bormant

пробел или иной символ это тоже просто символ можно всё через strstr() сделать, нашёл слово получил указатель потом с этого указателя дальше пошёл, что слово что подстрока не важно это всё одно и тоже, у нас грубо говоря есть массив символов и всё, а как это представлять дело удобства

Deleted
()
Ответ на: комментарий от vodz

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

Deleted
()

Используй изменяемые ассоциативные массивы.

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

нет разницы искать подстроку или перебирать посимвольно

Есть. Или вы парсите слова, а потом перебираете, либо вы вызываете сразу библиотечную strstr(), которая возможно написана со всякими там SIMD и сразу получите информацию, а есть хотя бы одна подстрока.

Короче, вот готовый вариант.

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

typedef struct MY_GETLINE_ARGS {
	char *lp;
	size_t n;
	const char *name;
} my_getline_args_t;
#define S(p_my_getline_args_t) ((p_my_getline_args_t)->lp)
#define U_C(s) (*((unsigned char *)(s)))

static my_getline_args_t *
my_getline(my_getline_args_t *a, FILE *in, const char *prmt)
{
	char *e;

	if(a == NULL)
		a = calloc(1, sizeof(*a));

	if(prmt != NULL)
		printf ("%s: ", prmt);

	errno = 0;
	if(getline(&a->lp, &a->n, in) < 0) {
		if(errno) {
			fprintf(stderr, "%s I/O error: %s\n", a->name, strerror(errno));
			exit(1);
		}
		if(a->name == NULL)
			exit(0);
		return NULL;
	}
	e = strchr(a->lp, '\n');
	if(e != NULL)
		*e = '\0';
	return a;
}

int
main ()
{
  int k = 0;
  FILE *myfile;
  my_getline_args_t *name;
  my_getline_args_t *word;
  my_getline_args_t line, *pline;
  char *p, *buf;
  size_t wl;

  name = my_getline(NULL, stdin, "Enter name of file");
  if ((myfile = fopen (S(name), "r")) == NULL) {
	fprintf(stderr, "%s %s\n", S(name), strerror(errno));
	return 1;
  }
  word = my_getline(NULL, stdin, "Enter word");
  wl = strlen(S(word));
  if(wl == 0) {
	fprintf(stderr, "word must not empty\n");
	return 2;
  }

  pline = memset(&line, 0, sizeof(line));
  pline->name = S(name);
  while((pline = my_getline(pline, myfile, NULL)) != NULL) {
	buf = S(pline);
	while((p = strstr(buf, S(word))) != NULL) {
		if((p != S(pline) && isspace(U_C(p-1)) == 0)
		|| (p[wl] != '\0' && isspace(U_C(p+wl)) == 0)) {
			buf++;
		} else {
			k++;
			buf = p + wl;
		}
	}
  }
  printf("%s have %d of `%s' words\n", S(name), k, S(word));
  /*
     Cleaning,  but do not need

     fclose(myfile);
     free(S(name));
     free(S(word));
     free(S(&line));
  */
  return 0;
}

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

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

Ну и как повод посмотреть в сторону is* макросов/функций.

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

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

Deleted
()
Ответ на: комментарий от bormant

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

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

Ну зачееем

Меня тут в соседних коментариях упрекнули, что сильно напирал на удочку, вместо рыбы, так что вот сделал наоборот, мне не трудно, я на C пишу быстро и легко.

Я сомневаюсь, что с этим он пойдёт сдаваться, этот код не по его знаниям.

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

Я сомневаюсь, что с этим он пойдёт сдаваться, этот код не по его знаниям.

Ну так то да )))) Ну ничего пускай разбирает код, понимать чужой код не менее важнее чем уметь писать свой ))

Меня тут в соседних коментариях упрекнули, что сильно напирал на удочку, вместо рыбы

Ну не без этого

Deleted
()

mmap() и ищи по памяти для начала, с этим-то проблем нет?

Sorcerer ★★★★★
()

а использование regex запрещено?

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

спасибо, всё работает только я в си день) до этого немного работал со скриптами на линукс

думаю за неделю розберусь))

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

или просто

#include <stdio.h>
#include <ctype.h>

int countwords(FILE *f, char *w)
{
        char *wm = w;
        char c;
        int n = 0, k = 1;
        while ((c = getc(f)) != EOF) {
                if (*wm == '\0') {
                        n++;
                        wm = w;
                        k = 0;
                }
                if (k && c == *wm++) {
                        k = 0;
                        wm = w;
                }
                if (isspace(c))
                        k = 1;
        }
        if (*wm == '\0')
                n++;
        return n;
}

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

чуть-чуть поправить только

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

или просто

Хрень какая-то. Я попробовал со словом из одного символа {, оно насчитало в 100 раз больше. Да и вообще, где проще то? Этот код заменяет только тот двухуровневый while, но считывает посимвольно файл. Прошли те времена, когда getc() был макросом: (file->bufptr == end ? fgetc() : *(file->bufptr)), теперь это макаронный код «а может вы таки юзаете треды?» с соотвествующим быстродействием. А вот над str*() наоборот корпят насчёт SIMD.

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

я конечно извиняюсь, но strstr оно не будет работать, так как у меня многострочный файл, да? просто я только что пробовал найти индекс слова в файле и мне показало число 1421446608

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

я конечно извиняюсь, но strstr оно не будет работать, так как у меня многострочный файл, да?

strstr ищет в строке. Можно, конечно, и закачать весь файл в буфер, но можно и обрабатывать файл построчно как я и сделал.

просто я только что пробовал найти индекс слова в файле и мне показало число 1421446608

кто «показало»? strstr() ? Так оно адрес слова в строке показывает.

vodz ★★★★★
()

всем спасибо за советы и готовые решения, но я слишком туп и неопытен, для понимания всего вышенаписанного

boxerwba
() автор топика
Ответ на: комментарий от i-rinat

Если ты вот так пишешь код, мне жаль людей, которые с тобой работают. :)

Как всегда, все такие загадочные... Если вы о том, получаю ли я денег за write-only код, то это вряд ли. Не потому, что могу, а потому что совесть не даёт так делать. Даже вон тот код уже переписал раза 3, найдя две принципиальные ошибки и одну смешную алгоритмическую описку (надо не buf++, а buf = p +1), хотя этот код никому он нафиг не сдался, а от его интерфейса, заданного ТСом всегда тошнило.

vodz ★★★★★
()

Сделай mmap файла в память — так будет шустрей. Дальше фигачь в цикле strstr или strnstr (если не нужно учитывать регистр). И все будет хорошо.

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

И все будет хорошо.

И тут придёт другой анонимус и скажет, а фигли вы в однобайтной кодировке работаете? Другой скажет, что grep -w работает по другому, у него слова - это всё что не isalnum+'_' и так далее. Не будет у него хорошо, а уж с mmap и тем более.

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

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

Тю, там было не дофига, а всего два free в комментариях(!) не указано. Тоже мне подвиг, искать плюхи в пятиминутном write-only коде. А как побыстроку кинуть рабочее - так в кусты. Вон только анонимус кинул, правда не понятно, где он вообще это откопал, ибо не рабочее ни разу.

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

Почему два?

В функции my_getline, выделяется память

a = calloc(1, sizeof(*a));
И есть
exit(1);
exit(0);
return NULL;
Так что как минимум тут 3 free. Так же не будет закрыт myfile при exit. ещё, вот тут myfile не закрывается
fprintf(stderr, "word must not empty\n");
return 2;

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

Ууу, как запущено. Вы не в курсе, что exit - это сискол: убей меня, я больше жить не хочу и забери все ресурсы? Причём быстро и качественно? А return из main - это правильный exit из всех возможных? Чего вы вообще влезли с такими познаниями то?

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

Cогласен был не прав, про exit. (Шок, в С можно не очищать за собой память, главное выходить через exit, я нуб :()

На такой код

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    char* a = (char*)calloc(1, 10);
    a[0]='a';
    //free(a);
    exit(0);
}

valgrind не даёт ошибок

valgrind --leak-check=full ./a.out 
==32501== Memcheck, a memory error detector
HEAP SUMMARY:
==32501==     in use at exit: 10 bytes in 1 blocks
==32501==   total heap usage: 1 allocs, 0 frees, 10 bytes 
allocated
==32501== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Но вот файлы, при return из main, всё же нужно закрывать

int main(void)
{
    FILE *myfile = fopen ("1.txt", "r");
    return 2;
}
cppcheck
Id: resourceLeak
Кратко: Resource leak: myfile
Сообщение: Resource leak: myfile

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

в С можно не очищать за собой память, главное выходить через exit, я нуб

В любой ОС, мало-мальски позиционирующей себя как многозадачная-многопользовательская есть похожий сискол. В C просто врапер, который перед самоубийством делает еще fflush_all().

Но вот файлы, при return из main, всё же нужно закрывать

Не верьте глазам своим. На самом деле это другая проблема: при fclose() может выскочить проблема fflush-а, то есть последняя запись буфера может не пройти. Но мы только читаем, потому плевать на статус fclose(), а в cppcheck поленились связать return из main с exit, хотя в райтаймовом стартапе происходит вот что:

_start(argc, argv, env) { exit(main(argc, argv, env)); }
vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.