LINUX.ORG.RU

История изменений

Исправление vodz, (текущая версия) :

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

Есть. Или вы парсите слова, а потом перебираете, либо вы вызываете сразу библиотечную 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, :

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

Есть. Или вы парсите слова, а потом перебираете, либо вы вызываете сразу библиотечную 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(1) {
	pline = my_getline(pline, myfile, NULL);
	if(pline == NULL)
		break;
	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 not need

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