NickYur Ответов: 3

Свободная память массива->строки в структуре


В основном это мой код.

Это функция, которая получает статическую строку и одинокую букву и берет все слова, начинающиеся с этой одинокой буквы, и копирует их в динамическую строку в динамическом массиве типа struct. Я пытаюсь освободить память но она всегда выходит из строя не знаю почему

Что я уже пробовал:

#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct string
{
	char *string;
	int size;
}String;

String *array_string(char *string, char letter, int **size);
void print_str(String *arr, int size);
void free_str(String *arr, int size);

void main()
{
	String *arr;
	int *size;
	char letter;
	char string[500];

	//Receiving static string from the user
	printf("Please enter a string\n");
	rewind(stdin);
	gets(string);

	//Receiving one letter from the user to find matching words
	printf("Enter any letter:\n");
	scanf_s("%c", &letter);

	printf("The string is:\n");
	printf("%s \n", string);

	arr = array_string(string, letter, &size);

	//Printing the matching words and then freeing the memory
	print_str(arr, size);
	free_str(arr, size);
	
	printf("\nEnd.\n");

}

String *array_string(char *string, char letter, int **size)
{
	String *arr;
	int i = 0, j = 0, k = 0;
	int size_arr = 0;
	int size_str = 0;

	//Counting number of matching words in given string
	if (string[i] == letter || string[i] == toupper(letter) || string[i] == tolower(letter))
		size_arr++;
	i++;
	for (; string[i] != '\0'; i++)
		if ((string[i - 1]) == ' ')
			if (string[i] == letter || string[i] == toupper(letter) || string[i] == tolower(letter))
				size_arr++;

	//Allocating dynamic array of struct type for matching words in given string
	arr = (String*)malloc(size_arr * sizeof(String));
	*size = size_arr;
	i = 0;

	//Counting number of letters in each matchin word and allocating dynamic string for each word
	if (string[j] == letter || string[j] == toupper(letter) || string[j] == tolower(letter))
	{
		while (string[j] != ' ' && string[j] >= 'A' && string[j] <= 'z')
		{
			size_str++;
			j++;
		}
		arr[i].string = (char*)malloc(size_str * sizeof(char));
		arr[i].size = size_str;
		size_str = 0;
		i++;
	}
	j++;
	while (i < size_arr)
	{
		for (; string[j] != '\0'; j++)
			if ((string[j - 1]) == ' ')
				if (string[j] == letter || string[j] == toupper(letter) || string[j] == tolower(letter))
				{
					while (string[j] != ' ' && string[j] != '\0' && string[j] >= 'A' && string[j] <= 'z')
					{
						size_str++;
						j++;
					}

					arr[i].string = (char*)malloc(size_str * sizeof(char));
					arr[i].size = size_str;
					size_str = 0;
					i++;
				}
	}
	i = 0;
	j = 0;

	//Copying the matching words to dynamic strings in dynamic array of struct type
	if (string[j] == letter || string[j] == toupper(letter) || string[j] == tolower(letter))
	{
		while (string[j] != ' ' && string[j] >= 'A' && string[j] <= 'z')
		{
			arr[i].string[k] = string[j];
			j++;
			k++;
		}
		arr[i].string[k] = '\0';
		i++;
		k = 0;
	}
	j++;
	while (i < size_arr)
	{
		for (; string[j] != '\0'; j++)
			if ((string[j - 1]) == ' ')
				if (string[j] == letter || string[j] == toupper(letter) || string[j] == tolower(letter))
				{
					while (string[j] != ' ' && string[j] != '\0' && string[j] >= 'A' && string[j] <= 'z')
					{
						arr[i].string[k] = string[j];
						j++;
						k++;
					}
					arr[i].string[k] = '\0';
					k = 0;
					i++;
				}
	}
	return arr;
}

//Print string
void print_str(String *arr, int size)
{
	int i;
	printf("The words are:\n");
	for (i = 0; i < size; i++)
		printf("%s ", arr[i].string);
	printf("\n");
}

//Free memory
void free_str(String *arr, int size)
{
	int i;
	for (i = 0; i < size; i++)
		free(arr[i].string);
	free(arr);
}

Rick York

Ник: код относится к разделу "что я пробовал", а текст-к разделу "описание проблемы".

3 Ответов

Рейтинг:
2

W∴ Balboos, GHB

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

Действительно ли массив выделен? В C вы можете записать в нераспределенный массив, а затем следить за результатами! Он будет принимать данные. То, что произойдет дальше, может быть чем угодно. Аналогично, вы можете попытаться освободить такой не-массив.

Это похоже на многомерный массив:
Итак, проверьте границы - выделяете ли вы достаточно элементов? Освобождая больше, чем вы выделяете?

То, что я использовал раньше, хотя это было в той конкретной реализации C и не было стандартным в то время: alloca() выделяла память в стеке, и она автоматически освобождалась, когда вы покидали функцию, в которой она была выделена. Вы все равно должны использовать malloc () и т. д., Если вам нужно, чтобы данные сохранялись за пределами функции.

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


Рейтинг:
2

Jochen Arndt

Он даже не должен компилироваться без предупреждения, потому что вы передаете неправильный тип для size параметры:

void free_str(String *arr, int size);

/* size is of type int* */
int *size;
arr = array_string(string, letter, &size);

/* size must be of type int here */
print_str(arr, size);
free_str(arr, size);
а также внутри самого array_string() функция, в которой вы назначаете int к int*:
/* size is of type int** and size_arr is of type int */
*size = size_arr;

Так что измените тип size переменная в вашем main функции int и параметр array_string() к int* Наконец, проверьте, назначает ли ваш код выделенную память всем arr члены (я этого не проверял).


Рейтинг:
0

CPallini

Вы должны быть очень осторожны при выделении/освобождении памяти. Я думаю, что лучше реализовать набор String функции обработки и простой конечный автомат для разбора входной строки.
Пожалуйста, обратите внимание: никогда не используйте gets функция.

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

// the 'String' data type
typedef struct
{
  char * s;
  int len;
} String;

//-> 'String' handling functions
// init (set empty) 
void initstring( String * ps)
{
  if ( ! ps ) return;
  ps->s = (char * ) 0;
}
// fills the content (copying from existing string): allocates memory 
void fillstring( String * ps, const char * beg, const char * end)
{
  if ( ! ps ) return;
  ps->len = end - beg;
  if ( ps->len < 1) return;
  ps->s = (char *) malloc( ps->len);
  if ( ! ps->s ) return;
  memcpy(ps->s, beg, ps->len);
}
// prints
void printstring(const String * ps)
{
  int i;
  if ( ! ps || ! ps->s) return;
  for ( i = 0; i< ps->len; ++i)
  {
    putchar(ps->s[i]);
  }
}
// clears the content: releases memory
void emptystring( String * ps)
{
  if ( ! ps || ! ps->s ) return;
  free( ps->s );
  ps->s = (char* ) 0;
}
//-< 'String' handling functions

enum // states of the 'nextword' function state-machine
{
  NOT_BLANK = 0,
  BLANK,
  MATCH
};

// finds the next word and assigns it to 'ps' (if not null)
// implements a simple state-machine
const char * nextword( const char * start, char letter, String * ps)
{
  const char *p = start;
  const char *beg = (const char *) 0;
  const char *end = (const char *) 0;

  int state = BLANK;

  while (*p != '\0' && ! end)
  {
    switch ( state )
    {
    case BLANK:
      if ( *p != ' ')
      {
        if ( toupper(*p) == toupper(letter))
        {
          state = MATCH;
          beg = p;
        }
        else
        {
          state = NOT_BLANK;
        }
      }
      break;
    case NOT_BLANK:
      if ( *p == ' ')
      {
        state = BLANK;
      }
      break;
    case MATCH:
      if ( *p == ' ')
      {
        end = p;
      }
      break;
    }
    ++p;
  }

  if ( state == MATCH )
  {
    if ( *p == '\0' ) end = p;

    if ( ps ) fillstring(ps, beg, end);
  }
  return end;
}

enum
{
  BUFSIZE = 512,
};

int main()
{
  char line[BUFSIZE];
  char letter;
  const char *p;
  int count = 0;

  printf("please enter a line a text:\n");

  if ( ! fgets(line, BUFSIZE, stdin) ) return -1;

  // remove the (possibly included) newline
  size_t len = strlen(line);
  if ( len > 0 && line[len-1] == '\n' )
    line[len-1] = '\0';


  printf("please insert a letter:\n");
  if ( scanf("%c", & letter) != 1)
    return -1;

  p = line;

  while ( 1 )
  {
    p = nextword( p, letter, (String * )0);
    if ( ! p  ) break;
    ++count;
  }

  printf("there are %d matches.\n", count);

  if ( count > 0)
  {
    int i;
    String * as = (String *) malloc ( count * sizeof ( String ));
    if ( ! as ) return -1;

    p = line;
    for ( i = 0; i < count; ++i)
      p = nextword( p, letter, &(as[i]));

    for ( i = 0; i< count; ++i)
    {
      printstring(&as[i]);
      printf("\n");
    }

    for ( i = 0; i < count; ++i)
      emptystring( &(as[i]));

    free(as);
  }
  return 0;
}