Click here to Skip to main content
15,889,462 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Basically this is my code.

Its a function that receiving a static string and a lone letter and takes all the words that starts with this lone letter and copying it to dynamic string in dynamic array of struct type. I'm trying to free the memory but it always crashes no idea why

What I have tried:

C++
#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);
}
Posted
Updated 4-May-18 5:06am
v2
Comments
Rick York 3-May-18 13:38pm    
Nick: the code belongs in "What I have tried" and the text in the problem description section.

Try using a debugger. See what it does at that point. The error message from your crash should also help.

Is the array actually allocated? In C, you can write to an unallocated array and then watch out for the results! It will accept the data. What happens next can be anything. Similarly, you could attempt to free such an non-array.

This seems like a multi-dimensional array:
So, check the bounds - are you allocating enough elements? Deallocating more than you allocate?

Something I used to used, although it was in that particular implementation of C and wasn't standard at the time: alloca() allocated memory on the stack, and it was automatically deallocated when you left the function in which it was allocated. You must still use malloc(), and such, if you need the data to persist beyond the function.

But the best way to do this is in a debugger. If you don't have or are unfamiliar with that, you really must change that to make your debugger your friend.
 
Share this answer
 
It should not even compile without a warning because you are passing a wrong type for the size parameters:
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);
and also inside the array_string() function where you assign an int to an int*:
/* size is of type int** and size_arr is of type int */
*size = size_arr;

So change the type of the size variable in your main function to an int and the parameter of array_string() to an int*. Finally check if your code assigns allocated memory to all arr members (I did not checked it).
 
Share this answer
 
You have to be very careful on memory allocation/deallocation. I think it is better to implement a set of String handling functions and a simple state machine to parse the input line.
Please note: never use the gets function.
C
#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;
}
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900