Trouble with dynamic input program in C - c

I am having debugging my program and I cannot seem to find any answers. My program takes in a file, copies the words to a dynamic array and keeps a word count for multiples.
Problem 1) For what I have compiled I have tried to different input examples. One reads "foo bar bat bam" and the other "foo foo bar bam". The first output is all four words in that order, the second prints
foo
bar
bam
foo bar bam
I cannot figure out why this is.
Problem 2) I am getting a segmentation fault when I try to initialize a newly entered word to count 1. The line
arrayOfWords[unique_words].count = 1;
is giving me a segmentation fault. And using -> does not compile.
Problem 3) I cannot seem to dynamically grow the array. I commented them out for now, but you can see my two strategies at attempting to enlarge the array.
I SERIOUSLY APPRECIATE YOUR HELP!
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INITIAL_SIZE 10
typedef unsigned int uint;
typedef struct { char * word; int count; } wordType;
int main( void )
{
wordType *arrayOfWords = (wordType*)malloc(1 * sizeof (wordType) );
wordType *tempArray;
FILE * inputFile;
char temp[50];
uint i;
uint j;
uint unique_words;
uint exists;
uint wordAdded;
inputFile = fopen( "input.txt", "r");
if( inputFile == NULL )
{
printf("Error: File could not be opened\n" );
/*report failure*/
return 1;
}
i = 0;
unique_words = 0;
wordAdded = 0;
while( fscanf( inputFile, "%s", temp) != EOF )
{
/*if a word was added, then increase the size by one
if( wordAdded == 1 )
{
tempArray = malloc((unique_words + 1) * sizeof(wordType) );
memcpy( arrayOfWords, tempArray, unique_words + 1 );
free( tempArray );
wordAdded = 0;
} */
/*
if( wordAdded == 1 )
{
arrayOfWords = realloc(arrayOfWords, unique_words + 1 );
wordAdded = 0;
}*/
exists = 0;
for( j = 0; j < unique_words; j++ )
{
if( strcmp( arrayOfWords[j].word, temp ) == 0 )
{
arrayOfWords[j].count++;
exists = 1;
}
}
if( exists == 0 )
{
arrayOfWords[unique_words].word = malloc(sizeof(char)
* (strlen(temp)+1));
strcpy( arrayOfWords[unique_words].word, temp );
/*arrayOfWords[unique_words].count = 1; */
unique_words++;
wordAdded = 1;
}
i++;
}
printf("unique_words = %d\n", unique_words);
for( i = 0; i < unique_words; i++ )
printf("%s\n", arrayOfWords[i].word);
fclose( inputFile );
/* for( i = 0; i < size; i++ )
free( arrayOfWords[0].word );*/
return 0;
}

int main( void ){
wordType *arrayOfWords = NULL;
FILE * inputFile = stdin; //stdin for simplification
char temp[50];
uint i,j;
uint unique_words;
uint exists;
unique_words = 0;
while( fscanf( inputFile, "%s", temp) != EOF ){
exists = 0;
for( j = 0; j < unique_words; j++ ){
if( strcmp( arrayOfWords[j].word, temp ) == 0 ){
arrayOfWords[j].count++;
exists = 1;
break;
}
}
if( exists == 0){//new word
arrayOfWords = realloc(arrayOfWords, (unique_words+1)*sizeof(wordType));
arrayOfWords[unique_words].count = 1;
arrayOfWords[unique_words].word = malloc(sizeof(char)*(strlen(temp)+1));
strcpy(arrayOfWords[unique_words].word, temp );
++unique_words;
}
}
printf("unique_words = %d\n", unique_words);
for( i = 0; i < unique_words; i++ )
printf("%s\n", arrayOfWords[i].word);
/* deallcate
for( i = 0; i < unique_words; ++i)
free( arrayOfWords[i].word );
free(arraOfWords);
*/
return 0;
}

You commented out the reallocation because it didn't work, and now it crashes because you don't reallocate.
Just like malloc, the realloc function needs the size in bytes. You should therefore use e.g.
arrayOfWords = realloc(arrayOfWords, sizeof(wordType) * (unique_words + 1));
When you get this reallocation working, your program should no longer crash.
And in case you're wondering, the crash is because you increase unique_words but do not reallocate the buffer. This leads you to access memory outside of the memory you allocated, which is undefined behavior and can lead to crashes (or other weird behavior).

Related

adding zeros before string

zfill algorithm is supposed to work as follows:
zfill function accepts two parameters, a string and a number,
if string length is >= the number, then it doesn't have to add anything, and it returns a copy to the string,
else, malloc enough space and add zeros before the string.
I'm trying to understand why is this solution not correct, it has two warnings:
1st warning:
for (i; i < zeros; i++) {
s[i] = "0";
}
"=": char differs in level of indirection from char[2]
2nd warning:
for (i; i < n; i++) {
s[i] = str[i];
}
buffer overrun while writing to s
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
free(s);
return 0;
}
EDIT: I've solved the problem this way:
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum-1] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = '0';
}
for (size_t j = 0; i < n; j++) {
s[i++] = str[j];
}
s[sum-1] = 0;
}
return s;
}
and it works, but I don't know why I have this warning:
for (i; i < zeros; i++) {}
statement with no effect
but when I've debugged I've noticed that this statement has an effect, because it correctly copies the correct number of zeros. I don't know why I have this warning
SO is a place of learning.
When first dealing with a coding challenge, it's best to take time to work out what's needed before starting to write code.
Below is a working version of zfill() (along with a main() that tests it.)
Read through the comments. The only thing new here is memset().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// A trivial "helper function" determines the max of two values
int max( int a, int b ) { return a > b ? a : b; }
char *zfill( char *str, int minLen ) {
// Determine length of arbitrary string
int len = strlen( str );
// Determine max of length v. minimum desired
int allocSize = max( minLen, len );
// allocate buffer to store resulting string (with '\0')
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
// determine start location at which to copy str
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
// fill buffer with enough 'zeros'
memset( obuf, '0', allocSize ); // ASCII zero!
// copy str to that location in buffer
strcpy( obuf + loc, str );
// return buffer to calling function
return obuf;
}
int main() {
// collection of strings of arbitrary length
char *strs[] = { "abc", "abcdefghijkl", "abcde", "a", "" };
// pass each one to zfill, print, then free the alloc'd buffer.
for( int i = 0; i < sizeof strs/sizeof strs[0]; i++ ) {
char *cp = zfill( strs[i], 10 );
puts( cp );
free( cp );
}
return 0;
}
Output:
0000000abc
abcdefghijkl
00000abcde
000000000a
0000000000
Here's zfill() without the comments:
char *zfill( char *str, int minLen ) {
int len = strlen( str );
int allocSize = max( minLen, len );
char *obuf = (char*)malloc( allocSize + 1 );
/* omitting test for failure */
int loc = len <= minLen ? minLen - len : 0;
if( loc > 0 )
memset( obuf, '0', loc ); // ASCII zero!
strcpy( obuf + loc, str );
return obuf;
}
You don't want to spend your time staring at lines and lines of code.
Fill your quiver with arrows that are (proven!) standard library functions and use them.
I've omitted, too, the test for zfill being passed a NULL pointer.
This code snippet
size_t sum = length + 1u;
s = malloc(sum);
//...
s[sum] = 0;
accesses memory outside the allocated character array because the valid range of indices is [0, sum). You need to write at least like
s[length] = 0;
In this code snippet
for (i; i < zeros; ++) {
s[i] = "0";
}
the expression s[i] represents a single object of the type char while on the right-hand side there is a string literal that as an expression has the type char *. You need to write at least
s[i] = '0';
using the integer character constant instead of the string literal.
In this code snippet
size_t i = 0;
for (i; i < zeros; i++) {
s[i] = "0";
}
for (i; i < n; i++) {
s[i] = str[i];
}
as the length of the string str can be less than n then this for loop
for (i; i < n; i++) {
s[i] = str[i];
}
accesses memory outside the string str.
Pay attention to that your function has redundant code. It can be written simpler.
The function can look for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
size_t i = 0;
size_t m = len < n ? n - len : 0;
for ( ; i < m; i++ )
{
result[i] = '0';
}
for ( ; i < n; i++ )
{
result[i] = s[i - m];
}
result[i] = '\0';
}
}
return result;
}
int main( void )
{
const char *s = "Hello";
size_t n = 10;
char *result = zfill( s, n );
if ( result ) puts( result );
free( result );
}
The program output is
00000Hello
Or as #Some programmer dude pointed to in his comment you can use the standard C function snprintf that alone performs the task. For example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * zfill( const char *s, size_t n )
{
char *result = NULL;
if ( s != NULL )
{
size_t len = strlen( s );
n = len < n ? n : len;
result = malloc( n + 1 );
if ( result )
{
int m = len < n ? n - len : 0;
snprintf( result, n + 1, "%.*d%s", m, 0, s );
}
}
return result;
}
int main( void )
{
char *p = zfill( "Hello", 5 );
if ( p ) puts( p );
free( p );
p = zfill( "Hello", 10 );
if ( p ) puts( p );
free( p );
}
The program output is
Hello
00000Hello
so you have 3 major problems in your code :
it's s[i] = '0'; not s[i] = "0";
it's s[i] = str[i - zeros]; not s[i] = str[i]; as the value of the i will be 27 in your test case : so it make sense to say s[27] because its size is about 41 but it doesn't make sense to say str[27] as its size is only about 13 in your test case , so you had to map the value 27 of i to the value 0 to be convenient to use with str
i is deprecated in first part here for (i; i < zeros; i++) , so use for (; i < zeros; i++)instead of for (i; i < zeros; i++) , but it will not cause any problem if you keep it.
and here is the full edited code :
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char* zfill(const char* str, size_t n) {
if (str == NULL) {
return NULL;
}
char* s;
size_t length = strlen(str);
if (length >= n) {
//it doesn't have to add anything, just malloc and copy the string
size_t sum = length + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
for (size_t i = 0; i < length; i++) {
s[i] = str[i];
}
s[sum] = 0;
}
else {
// add zeros before strings
size_t zeros = n - length;
size_t sum = n + 1u;
s = malloc(sum);
if (s == NULL) {
return NULL;
}
size_t i = 0;
for (; i < zeros; i++) {
s[i] = '0';
}
for (; i < n; i++) {
s[i] = str[i - zeros];
}
s[sum] = 0;
}
return s;
}
int main(void) {
char str[] = "hello, world!";
size_t n = 40;
char* s = zfill(str, n);
printf("%s\n", s);
free(s);
return 0;
}

I want to create my own tail command with using getline and wihout use of lseek and fseek

I implemented below code but i want tailbuf[] should be in order. I want tailbuf[9] should be last line, tailbuf[8] second and so on. Please help me how i cant implement that in this code.
#include<stdio.h>
#include<stdlib.h>
char ** lastnumlines(FILE *fp, unsigned int num)
{
int count = num;
int n, i, iNo1 = 0, iNo2= 0,z = 0;
size_t MAXSIZE = 1024;
char **tailbuf=calloc(count, sizeof(char *));
for (i = 0; i < count; i++)
{
tailbuf[i] = calloc(MAXSIZE, sizeof(char));
}
while (getline(&tailbuf[iNo2], &MAXSIZE, fp) != EOF)
{
iNo2 = (iNo2 + 1) % count;
if (iNo2 == iNo1)
{
iNo1 = (iNo1 + 1) % count;
}
}
i = iNo2;
int k = 0;
do{
printf("%s\n",tailbuf[i]);
i = (i+1) % count;
}while (i != iNo2);
free(tailbuf);
}
int main()
{
char *filename = "demo1.txt";
FILE *fp = fopen(filename,"r");
if(fp == NULL)
{
printf("Unable to open file!\n");
exit(1);
}
lastnumlines(fp,10);
fclose(fp);
return 0;
}
How i can tailbuf in order?
A simple solution should be to have two arrays of lines pointers (note that the memory won't be duplicated)
a circular buffer to read the file without other difficulty than using a mod op %
a linear buffer reordering the read line to be used elsewhere:
void lastnumlines(FILE *fp, unsigned int num)
{
/* variable names have been made more expressive */
int i;
size_t size = 1024;
char **tailbuf=calloc(num, sizeof(char *));
char **circbuf=calloc(num, sizeof(char *));
int index_in_buff = 0;
int line_no = 0;
for (i = 0; i < num; ++i) {
circbuf[i] = malloc(size);
}
/* get lines in circular buffer */
while (getline(&circbuf[index_in_buff % num], &size, fp) != EOF)
{
++index_in_buff;
++line_no;
}
/* reorder lines from circular to linear buffer */
for (i = 0; i < num; ++i) {
printf("%d --> %d\n", (line_no+i)%num, i);
tailbuf[i] = circbuf[(line_no+i)%num];
}
/* display lines, warning, some may be null if num > line_no */
for (i = 0; i < num; ++i) {
if (tailbuf[i])
printf("%s", tailbuf[i]);
}
/* cleanup memory */
for (i = 0; i < num; ++i) {
free(tailbuf[i]);
}
free(tailbuf);
free(circbuf);
}
Note that the circbuf can be deleted at the end of function, and tailbuf can be returned to be used in other functions. Both tailbuf and circbuf point to line memory, but there is no deep bind.
Here's a sketch of how you could do this with a single array of pointers.
Up to 10 lines populate pArr pointers, then memmove will "scroll-up" the array so that the 'next' read is always to the final pointer.
const int n = 10; // Want last 10 lines. (fewer if short input).
char *pArr[ n ];
for( int i = 0; i < n; i++ )
pArr[ i ] = calloc( 128, sizeof(char) );
int lcnt = 0, retCode = 0;
while( retCode != EOF ) {
if( lcnt == n - 1 ) {
char *hold = pArr[0];
memmove( pArr, pArr + 1, (n - 1) * sizeof(pArr[0]) );
pArr[ lcnt ] = hold;
}
retCode = getline( pArr[ lcnt ], size, fp );
if( ++lcnt == n )
lcnt--;
}
for( i = 0; i <= lcnt; i++ )
printf( ... );
for( i = 0; i < n; i++ )
free( pArr[ i ] );

Heap buffer overflow caused by single line

Currently trying to work on my C (very new to it) by doing some leetcode questions. I'm puzzled by this issue, as it gives me a heap buffer overflow but only because of a single line. interpret() is called and passed a string command where 1 <= command.length <= 100, and will consist of "G", "()", and/or "(al)" in some order, with no other characters appearing.
char * interpret(char * command){
char * ret = malloc(sizeof(char) * 100);
int counter = 0;
for(int i = 0; i < sizeof(command) - 1; i++)
{
if(command[i] == 'G')
{
ret[counter] = 'G';
counter ++;
}
else if(command[i] == '(')
{
if (command[i + 1] == ')')
{
ret[counter] = 'o';
counter ++;
}
else
{
//ret[counter] = 'a'; ***********
ret[counter + 1] = 'l';
counter += 2;
}
}
ret[counter] = '\0';
}
return realloc(ret, counter * sizeof(char));
}
If the starred line is uncommented, then the entire program crashes in leetcode, but works fine on VSCode and returns the correct solution. I would appreciate any help, I'm sure it's something small I'm missing. Thanks.
ETA: Here is the leetcode problem in question
The parameter command has the pointer type char *.
So the operator sizeof applied to the pointer yields the size of the pointer instead of the length of the pointed string
for(int i = 0; i < sizeof(command) - 1; i++)
You could just write
for( size_t i = 0; command[i] != '\0'; i++)
Also it is unclear why there is used the magic number 100
char * ret = malloc(sizeof(char) * 100);
You could at first count the result characters and then allocated an array of the appropriate size and fill it.
Moreover due to this statement
ret[counter] = '\0';
(that is also unclear why it is within the for loop) you need to allocate an array with counter + 1 characters instead of counter characters as you are doing
return realloc(ret, counter * sizeof(char));
A straightforward approach can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * interpret( const char *command )
{
size_t n = 0;
for ( size_t i = 0; command[i] != '\0'; )
{
if ( command[i] == 'G' )
{
++n;
++i;
}
else if ( strncmp( command + i, "()", 2 ) == 0 )
{
++n;
i += 2;
}
else if ( strncmp( command + i, "(al)", 4 ) == 0 )
{
n += 2;
i += 4;
}
else
{
++i;
}
}
char *result = malloc( n + 1 );
if ( result != NULL )
{
n = 0;
for ( size_t i = 0; command[i] != '\0'; )
{
if ( command[i] == 'G' )
{
result[n++] = 'G';
++i;
}
else if ( strncmp( command + i, "()", 2 ) == 0 )
{
result[n++] = 'o';
i += 2;
}
else if ( strncmp( command + i, "(al)", 4 ) == 0 )
{
result[n++] = 'a';
result[n++] = 'l';
i += 4;
}
else
{
++i;
}
}
result[n] = '\0';
}
return result;
}
int main( void )
{
char *s = interpret( "G()(al)" );
if ( s ) puts( s );
free( s );
s = interpret( "(al)G(al)()()G" );
if ( s ) puts( s );
free( s );
}
The program output is
Goal
alGalooG
Pass the size of command to interpret.
In C, when you pass a string to a function, you’re not actually passing the full string, you’re passing a pointer to the first element in the string. This becomes an issue when you do sizeof(command), as you're just getting the size of the pointer and not the full string. If you try to loop over this string as done in the question, this can either lead to an underread, if you have a string longer than sizeof(char*), or a buffer overflow, if you have a string shorter than sizeof(char*). Generally, you shouldn’t use sizeof on pointers.
To fix your code, use strlen on the string you're passing to command in the calling function and do something similar to this:
char * interpret(char * command, int size){
char * ret = malloc(sizeof(char) * 100);
int counter = 0;
for(int i = 0; i < size; i++)
{ ...

How to properly access this realloc-ed array?

In this code below I am trying to create an array of ints that can be accessed from the main() function, however, Address-sanitizer gives me stack-buffer-overflow-error and I cannot figure out what I am doing wrong. What am I missing?
#include <stdlib.h>
void reallocFail(int **arrayOfInts) {
*arrayOfInts = (int *)malloc(sizeof(int));
for (int i = 1; i <= 10; i++) {
*arrayOfInts = (int *)realloc(*arrayOfInts, (i) * sizeof(int));
*arrayOfInts[i - 1] = i;
}
}
int main(void) {
int *arrayOfInts;
reallocFail(&arrayOfInts);
return 0;
}
There is just a simple typo in *arrayOfInts[i - 1] = i;. suffix operators such as [] bind stronger than prefix operators such as *. Hence you should write:
(*arrayOfInts)[i - 1] = i;
Note also that you should check for memory reallocation failure and you can initialize *arrayOfInts to NULL as realloc(NULL, size) is equivalent to malloc(size).
Here is a modified version:
#include <string.h>
#include <stdlib.h>
int reallocFail(int **pp, int n) {
int i;
*pp = NULL;
for (i = 0; i < n; i++) {
int *p = realloc(*pp, (i + 1) * sizeof(*p));
if (p == NULL)
break;
p[i] = i + 1;
*pp = p;
}
return i;
}
int main(void) {
int *arrayOfInts = NULL;
int n = reallocFail(&arrayOfInts, 10);
for (int i = 0; i < n; i++) {
printf("%d%c", arrayOfInts[i], " \n"[i == n-1]);
}
free(arrayOfInt);
return 0;
}
void reallocFail(int **arrayOfInts)
{
for (int i = 1; i <= 10; i++)
{
*arrayOfInts = realloc(*arrayOfInts, i * sizeof(**arrayOfInts));
arrayOfInts[0][i - 1] = i;
}
}
int main(void) {
int *arrayOfInts = NULL;
reallocFail(&arrayOfInts);
return 0;
}
But this code can be reduced to one realloc (I understand that you test if realloc works).
IT does not check if the realloc has succeeded or failed:
void reallocFail(int **arrayOfInts)
{
int *tmp;
for (int i = 1; i <= 10; i++)
{
tmp = realloc(*arrayOfInts, i * sizeof(**arrayOfInts));
if(tmp)
{
*arrayOfInts = tmp;
arrayOfInts[0][i - 1] = i;
}
else
printf("Alloction error\n");
}
}
For starters this memory allocation before the for loop
*arrayOfInts = (int*)malloc(sizeof(int));
is redundant. You could just write
*arrayOfInts = NULL;
Also you need to check whether memory allocation was successful.
Also this record
*arrayOfInts[i-1] = i;
is equivalent to
*( arrayOfInts[i-1] ) = i;
but you need
( *arrayOfInts )[i-1] = i;
The function can look the following way
size_t reallocFail( int **arrayOfInts, size_t n )
{
*arrayOfInts = NULL;
size_t i = 0;
if ( n != 0 )
{
int *tmp = NULL;
do
{
tmp = realloc( *arrayOfInts, ( i + 1 ) * sizeof( int ) );
if ( tmp != NULL )
{
tmp[i] = i + 1;
*arrayOfInts = tmp;
}
} while ( tmp != NULL && ++i != n );
}
return i;
}
And the function can be called for example like
int *arrayOfInts = NULL;
size_t n = reallocFail( &arrayOfInts, 10 );
for ( size_t i = 0; i != n; i++ )
{
printf( "%d ", arrayOfInts[i] );
}
putchar( '\n' );
free( arrayOfInts );
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
size_t reallocFail( int **arrayOfInts, size_t n )
{
*arrayOfInts = NULL;
size_t i = 0;
if ( n != 0 )
{
int *tmp = NULL;
do
{
tmp = realloc( *arrayOfInts, ( i + 1 ) * sizeof( int ) );
if ( tmp != NULL )
{
tmp[i] = i + 1;
*arrayOfInts = tmp;
}
} while ( tmp != NULL && ++i != n );
}
return i;
}
int main( void )
{
int *arrayOfInts = NULL;
size_t n = reallocFail( &arrayOfInts, 10 );
for ( size_t i = 0; i != n; i++ )
{
printf( "%d ", arrayOfInts[i] );
}
putchar( '\n' );
free( arrayOfInts );
return 0;
}
The program output is
1 2 3 4 5 6 7 8 9 10
Of course there is no great sense to reallocate the memory in the loop within the function. The function just demonstrates how to manage the function realloc.

How to read UFT8 text file and show how many time the word occur in the text

I'm trying to read the utf8 text file and print it out and count how many times it occurs For example The World is good ∮ E⋅da = Q, n → ∞, ∑ f(i) and it should show like
t->1
h->1
e->1
and so on. But it only can read the regular character and it can't read the utf8 character. Please help me
# include <stdio.h>
# include <string.h>
# include <stdbool.h>
int main(int argc, char **argv)
{
FILE *filePointer ;
char data[50];
int idx[50];
int cnt[50];
char unq[50];
filePointer = fopen("test.txt", "r") ;
if ( filePointer == NULL )
{
printf( "file failed to open." ) ;
}
else
{
// using fgets() method
while( fgets ( data, 50, filePointer ) != NULL )
{
// Print the dataToBeRead
//printf( "%s" , data ) ;
}
// Closing the file using fclose()
fclose(filePointer) ;
// printf("\nDone.\n") ;
}
int id=0;
//printf( "%d" , strlen(data) );
for (int i = 0; i < strlen(data); i++){
bool appears = false;
for (int j = 0; j < i; j++){
if (data[j] == data[i]){
appears = true;
break;
}
}
if (!appears){
unq[id]=data[i];
//printf( "writing %d%d",id,i );
id++;
}
}
printf( "\nunique characters \n%s" , unq );
printf( "\ntheir frequencies \n");
for (int i = 0; i < strlen(unq); i++){
int ctr=0;
for (int j = 0; j < strlen(data); j++){
if (data[j] == unq[i]){
ctr++;
}
}
cnt[i]=ctr;
printf("%c->%d\n",unq[i],cnt[i]);
}
printf( "\n" ) ;
return 0;
}

Resources