Reading input char by char using realloc in C - c

I would like to read input char by char and save it as a word into char* array. I don't know how long the input will be, so i want to alloc the memmory dynamicaly. The program ends,when the char is whitespace. How can i do this using realloc?
There is my code:
#include <stdio.h>
int main(void) {
char *word=malloc(1*sizeof(char));
char c;
int numOfChars=0;
c=getchar();
word[0]=c;
numOfChars++;
while((c=getchar())!=' '){
numOfChars++;
realloc(word,numOfChars);
word[numofChars-1]=c;
}
printf("%s", word);
return 0;
}
Example input:Word
Example output:Word

The program can look the following way. Take into account that the input is buffered and filled until a new line character is entered that is also a white space character. And the result word must be zero terminated if you are going to use format specifier %s to output it.
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main( void )
{
int c;
size_t n;
char *word;
char *tmp;
n = 0;
word = malloc( n + 1 );
word[n++] = '\0';
printf( "Enter a word: " );
while ( ( c = getchar() ) != EOF && !isspace( c ) && ( tmp = realloc( word, n + 1 ) ) != NULL )
{
word = tmp;
word[n-1] = c;
word[n++] = '\0';
}
printf( "You've entered \"%s\"\n", word );
free( word );
}
The program output might look like
Enter a word: Hello
You've entered "Hello"

In order to explain what I had in mind, i quickly set up this little programm to explain how to use an exponential growth :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INITIAL_CAPACITY 100
#define GROW_FACTOR 1.5
struct string_buffer {
size_t capacity;
size_t length;
char *buffer;
};
typedef struct string_buffer string_buffer_t;
string_buffer_t *sb_init(void);
static void sb_grow(string_buffer_t *sb);
void sb_shrink(string_buffer_t *sb);
char *sb_release(string_buffer_t *sb);
void sb_append_char(string_buffer_t *sb, char c);
char *sb_peek_string(string_buffer_t *sb);
int main(void)
{
string_buffer_t *sb=sb_init();
int c;
while ( (c=getchar())!=' ' && c!='\n' && c!=EOF )
sb_append_char(sb, c);
char *string=sb_release(sb);
printf("string : \"%s\"\nlength : %zu\n", string, strlen(string));
free(string);
return 0;
}
string_buffer_t *sb_init(void)
{
string_buffer_t *new=malloc(sizeof *new);
if (new==NULL) exit(EXIT_FAILURE);
new->capacity=INITIAL_CAPACITY;
new->length=1;
new->buffer=malloc(INITIAL_CAPACITY);
if (new->buffer==NULL) exit(EXIT_FAILURE);
new->buffer[0]=0;
return new;
}
static void sb_grow(string_buffer_t *sb)
{
char *new=realloc(sb->buffer, (size_t) (GROW_FACTOR*sb->capacity));
if (new==NULL) exit(EXIT_FAILURE);
sb->capacity=(size_t) (GROW_FACTOR*sb->capacity);
sb->buffer=new;
}
void sb_shrink(string_buffer_t *sb)
{
char *new=realloc(sb->buffer, sb->length);
if (new==NULL) exit(EXIT_FAILURE);
sb->buffer=new;
}
char *sb_release(string_buffer_t *sb)
{
sb_shrink(sb);
char *string=sb->buffer;
free(sb);
return string;
}
void sb_append_char(string_buffer_t *sb, char c)
{
if (sb->capacity==sb->length) sb_grow(sb);
sb->buffer[sb->length-1]=c;
sb->buffer[sb->length]=0;
sb->length=sb->length+1;
}

This will do
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *ptr;
char *word=malloc(1*sizeof *word);
char c;
int numofChars=0;
printf("Enter string terminated by a space :");
c=getchar();
word[0]=c;
numofChars++;
while((c=getchar())!=' '){
numofChars++;
ptr=realloc(word,numofChars*sizeof *ptr);
if(ptr!=NULL)
{
word=ptr;
word[numofChars-1]=c;
}
}
/* You need to append a null character to make it a valid string */
numofChars++;
ptr=realloc(word,numofChars*sizeof *ptr);
if(ptr!=NULL)
{
word=ptr;
word[numofChars-1]='\0';
}
printf("Word : %s\n", word);
free(word); // Freeing word/
return 0;
}
Well, you may write a function to replace
numofChars++;
ptr=realloc(word,numofChars*sizeof *ptr);
if(ptr!=NULL)
{
word=ptr;
word[numofChars-1]='\0';
}
Note:
It is not suggested that you do
word=realloc(word,numOfChars*sizeof(char));
because in case realloc fails, you have memory leak. So I used ptr here.

Related

How do I write a recursive function to print a string in reverse in C?

I need any given string to be printed in reverse using recursion. I have tried changing the function prototype and definition by changing the return value type and parameter list of the function stringReverse. stdout of this does not print anything for the reverse string and I cannot figure out why.
#include <stdio.h>
#define SIZE 100
char stringReverse(void);
size_t i;
unsigned int pass;
int hold;
char a1[SIZE];
char a2[SIZE];
int main(void) {
for (i = 0; i < SIZE; ++i) {
a1[i] = 0;
}
printf("Enter a string: ");
scanf_s("%[^\n]99s", a1);
printf("%s%s\n\n", "string is:\n", a1);
stringReverse();
}
char stringReverse(void)
{
for (pass = 1; pass < SIZE; ++pass) {
if (a1[i] < a1[i + 1]) {
hold = a1[i];
a1[i] = a1[i + 1];
a1[i + 1] = hold;
}
}
printf("%s%s", "reverse is:\n", a2);
}
You do not have a recursive function that outputs a string in the reverse order. Also it is a bad idea when a function depends on a global variable.
The function can look the following way as it is shown in the demonstrative program below. Using the function you will be able to output a string in the reverse order in any stream for example in a file.
#include <stdio.h>
FILE * string_reverse_output( const char *s, FILE *fp )
{
if ( *s )
{
string_reverse_output( s + 1, fp );
fputc( *s, fp );
}
return fp;
}
int main(void)
{
fputc( '\n', string_reverse_output( "Hello World!", stdout ) );
return 0;
}
The program output is
!dlroW olleH
below are recursive functions to reverse a string the first is only prints and the second build the string inside revstr buffer and return it to caller.
void reverse(char *str)
{
if (*str)
{
reverse(str+1);
printf("%c", *str);
}
}
void recrev(char* str, char* revstr, int i)
{
if (*str)
{
recrev(str+1, revstr, i-1);
sprintf(revstr + i, "%c", *str);
}
}
int main()
{
char arr[]="hello";
char revstr[6];
recrev(arr, revstr, 4);
printf("%s",revstr);
return 0;
}
Recursion is a massive overkill for this job. But still, if need be, #VladfromMoscow has given an excellent answer using recursion. Might I take the liberty to instead suggest a better solution altogether?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
printf("Enter your string: ");
char str[100];
scanf("%[^\n]s",str);
str = strrev(str);
printf("%s",str);
return 0;
}
For more information on how strrev works, I suggest you take a look at strrev() function in C
#include <stdio.h>
void reverse();
int main()
{
printf("Enter String : ");
reverse();
return 0;
}
void reverse()
{
char c;
scanf("%c", &c);
if (c != '\n')
{
reverse();
printf("%c", c);
}
}

Unique Words Counter in C

I'm programming a little programm in C wich should count unique words in c.
To do this, i'm having an wordbook to store all found words. Normaly it should only put words inside that aren't already in it but it keeps entering all writen words.
How can i fix this and how can i delete all the empty parts in my wordbook "woerterbuch" ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char lies_wort(char *Text);
char suche_wort(char *wort);
char neues_wort(char *wort);
char *woerterbuch[1000];
int main(void)
{
char Text[1000];
printf("Bitte Text eingeben : \n") ;
fgets (Text, 1000, stdin);
lies_wort(Text);
int i;
for(i=0;i<1000;i++){
printf("woerterbuch :%s\n",woerterbuch[i]);}
}
char lies_wort(char *Text){
char *wort;
int i=1;
wort = strtok(Text, " ,.!?;:");
while(wort != NULL) {
suche_wort(wort);
printf("gefunden %d: %s\n", i++, wort);
wort = strtok(NULL, " ,.!?;:");}
}
char suche_wort(char *wort)
{
int i;
for (i = 0; i>1000; i++){
if (!strcmp(woerterbuch[i],wort)){return 0;}}
neues_wort(wort);
return 0;
}
char neues_wort(char *wort)
{
int i;
for (i=0; i<1000; i++){
if(woerterbuch[i]==0){
woerterbuch[i]=wort;
return 0;}}
}
For Testing this programm is just printing all words in "woerterbuch" so i can check if it's working.
In suche_wort
for (i = 0; i>1000; i++)
It should be
for (i = 0; i<1000; i++)
Your loop is terminating right away everytime.
I believe you have some issues in your code:
Firstly, in this line:
woerterbuch[i]=wort;
Will only overwrite the address of woerterbuch[i], and this will lead to wrong results. Instead you need to allocate space for worterbuch[i], via malloc or strdup.
You can use allocate space for a single pointer like this:
worterbuch[i] = malloc(strlen(wort)+1);
Note: It is always good to check the return from malloc(), and free() these pointers at the end.
Now, since the pointer is pointing somewhere, you can copy stuff into it. You can use strcpy to do this. If you want to skip this copy step, you can just use strdup() instead.
Secondly, instead of globally defining char *woerterbuch[1000];, you can manage this array of pointers in a struct:
typedef struct {
char *woerterbuch[1000];
size_t n;
} worterbuch;
Which will make it easier to manage your array.
Thirdly, you are not checking the return of fgets(). This can return NULL if unsuccessful. You should also check for buffer overflow here.
Lastly, if their are a lot of words in your worterbuch, it might not be efficient to use linear search to check for duplicates. This process is O(N) time on average. Instead, you can use binary search, which is O(logN) on average, therefore much more efficient if n becomes very large.
Here is some code I wrote a while ago which does something similar:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TEXTSIZE 1000
typedef struct {
char *dictionary[TEXTSIZE];
size_t numwords;
} dictionary_t;
void read_text(char *text);
void read_words(char *text, dictionary_t *dict);
int search_word(dictionary_t *dict, char *word);
void print_words(dictionary_t *dict);
int str_cmp(const void *a, const void *b);
int main(void) {
dictionary_t dict;
char text[TEXTSIZE];
read_text(text);
read_words(text, &dict);
print_words(&dict);
return 0;
}
void read_text(char *text) {
size_t slen;
printf("Please enter text: \n");
if (fgets(text, TEXTSIZE, stdin) == NULL) {
fprintf(stderr, "Error reading text\n");
exit(EXIT_FAILURE);
}
/* removes '\n' character from fgets(), and checks for overflow */
slen = strlen(text);
if (slen > 0) {
if (text[slen-1] == '\n') {
text[slen-1] = '\0';
} else {
printf("Buffer overflow detected.\n");
exit(EXIT_FAILURE);
}
}
if (!*text) {
printf("No text entered.\n");
exit(EXIT_FAILURE);
}
}
void read_words(char *text, dictionary_t *dict) {
char *word;
const char *delim = " ,.!?;:";
dict->numwords = 0;
word = strtok(text, delim);
while (word != NULL) {
if (search_word(dict, word)) {
/* allocate space for ptr */
dict->dictionary[dict->numwords] = malloc(strlen(word)+1);
if (!dict->dictionary[dict->numwords]) {
printf("Cannot allocate word.\n");
exit(EXIT_FAILURE);
}
/* copy it into array */
strcpy(dict->dictionary[dict->numwords], word);
/* increment count, ready for next word */
dict->numwords++;
}
word = strtok(NULL, delim);
}
}
/* linear searching the word */
int search_word(dictionary_t *dict, char *word) {
size_t i;
for (i = 0; i < dict->numwords; i++) {
if (strcmp(dict->dictionary[i], word) == 0) {
return 0;
}
}
return 1;
}
/* cmp function for sorting dictionary */
int str_cmp(const void *a, const void *b) {
const char **str1 = (const char **)a;
const char **str2 = (const char **)b;
return strcmp(*str1, *str2);
}
void print_words(dictionary_t *dict) {
size_t i;
/* sort using qsort */
qsort(dict->dictionary, dict->numwords, sizeof(*(dict->dictionary)), str_cmp);
printf("\nDictionary:\n");
for (i = 0; i < dict->numwords; i++) {
printf("%s\n", dict->dictionary[i]);
/* freeing memory previosly allocated from malloc() */
free(dict->dictionary[i]);
dict->dictionary[i] = NULL;
}
}

C function to capitalize the first character of a pointer string

I want to capitalize the first character of a pointer string.
For example, input: john
Output: John
I can do it with arrays (s[0] = toUpper(s[0]), but is there a way to do it with pointers?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX 30
int transform(char *s)
{
while (*s != '\0')
{
*s = toupper(*s);
s++;
}
return *s;
}
int main()
{
printf("String: ");
char *s[MAX];
getline(&s,MAX);
transform(s);
printf("Transformed char: %s", &s);
}
int getline(char *s, int lim)
{
int c;
char *t=s;
while (--lim>0 && (c=getchar())!=EOF && c!='\n') *s++=c;
*s='\0';
while (c!=EOF && c!='\n')
c=getchar();
return s-t;
}
This code turns the whole string to upper case.
Your transform function is looping through the entire string and running toupper on each one. Just run it on the first character:
void transform(char *s)
{
*s = toupper(*s);
}
Also, you declare s in main as an array of pointers to char. You just want an array of char:
int main()
{
printf("String: ");
char s[MAX];
getline(s,MAX); // don't take the address of s here
transform(s);
printf("Transformed char: %s", s); // or here
}
You want to move main to the end of the file as well, so that getline is defined before it is called.
Easy solution:
void transform(char* p) {
//Only first character
*p = toupper(*p);
}
//Call like that:
char str[] = "test";
transform(str); //str becomes: "Test"

conflicting types for function returning a char array

Here's my code:
#include <stdio.h>
#include <string.h>
char input_buffer[1000];
void get_substring(){
int i;
int length;
printf("Please enter a string:\n");
scanf("%[^\n]s", input_buffer);
printf("Index of first character of substring:\n");
scanf("%d", &i);
printf("Length of substring:\n");
scanf("%d", &length);
printf("Substring is %.*s ", length, input_buffer + i);
}
int main(void) {
// your code goes here
//get_substring(0,4);
get_substring();
return 0;
}
That's my current code, I want to return a pointer of the input, instead of just displaying the substring. Sorry for the confusion everyone.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getSubstring(char* str,size_t start, size_t length)
{
// determine that we are not out of bounds
if(start + length > strlen(str))
return NULL;
// reserve enough space for the substring
char *subString = malloc(sizeof(char) * length);
// copy data from source string to the destination by incremting the
// position as much as start is giving us
strncpy(subString, str + start, length);
// return the string
return subString;
}
int main(int argc, char* argv[])
{
char *str = "Hallo Welt!";
char *subStr = getSubstring(str,0,20);
if(subStr != NULL)
{
printf("%s\n",subStr);
free(subStr);
}
}
This solution should give you a hint how you would start with such a problem.

Tokenized string of char to ints using atoi

I am trying to take user input: (1 345 44 23) and make it into a tokenized char string then into ints. Surprisingly I could not find much help for what I would think would be a common task.
Any ideas how to convert the char string into an in string using tokens?
My program crashes when it gets to the conversion (after the tokenization [I realize this is not a word]).
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define StrSZE 81
void strInput (char str[], int maxChars);
void custatoi(char * tokenArray[], int * data, int numOfTok);
int main(int argc, char *argv[])
{
char str[StrSZE];
char* tokenArray;
int maxChars=StrSZE-1, cont=1, numOfToken=0, i=0;
int* data;
strInput(str, maxChars);
tokenArray = strtok(str, " \t");
while (tokenArray)
{
printf("token: %s\n", tokenArray);
tokenArray = strtok(NULL, " \t");
numOfToken++;
}
data = (int *) malloc(numOfToken * sizeof(int));
custatoi(tokenArray, data, numOfToken);
system("PAUSE");
return 0;
}
void strInput (char str[], int maxChars)
{
char garbage;
int k=0;
str[0]='\0';
printf("Please type a string of whole numbers (intigers).\n\n");
while ((k<80) && ((str[k] = getchar()) != '\n'))
k++;
/* Clears the keyboard buffer. */
if (k==80)
while((garbage = getchar()) != '\n')
;
/* Place null at the end of the line read in from user */
str[k]='\0';
printf("str after input is: %s\n\n", str);
}
void custatoi(char * tokenArray[], int * data, int numOfTok)
{
int i;
for (i=0; i < numOfTok; i++)
data[i] = atoi(tokenArray[i]);
}
I corrected the errors in yours code: There was some mistakes in main(), tokenArray data type was not correct.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define StrSZE 81
void strInput (char str[], int maxChars);
void custatoi(char* tokenArray[], int * data, int numOfTok);
int main(int argc, char *argv[])
{
char str[StrSZE];
int maxChars=StrSZE-1, cont=1, numOfToken=0, i=0;
int* data;
char* tokenArray[50]; // Declared correctly
strInput(str, maxChars);
tokenArray[i] = strtok(str, " \t"); // Also made a change here!
while (tokenArray[i])
{
printf("token: %s\n", tokenArray[i]);
i++;
tokenArray[i] = strtok(NULL, " \t");
numOfToken++;
}
data = (int *) malloc(numOfToken * sizeof(int));
custatoi(tokenArray, data, numOfToken);
printf("data\n");
for(i=0;i<numOfToken;i++){
printf(" %d\n",data[i]);
}
system("PAUSE");
return 0;
}
void strInput (char str[], int maxChars)
{
char garbage;
int k=0;
str[0]='\0';
printf("Please type a string of whole numbers (intigers).\n\n");
while ((k<80) && ((str[k] = getchar()) != '\n'))
k++;
/* Clears the keyboard buffer. */
if (k==80)
while((garbage = getchar()) != '\n')
;
/* Place null at the end of the line read in from user */
str[k]='\0';
printf("str after input is: %s\n\n", str);
}
void custatoi(char* tokenArray[], int * data, int numOfTok)
{
int i;
for (i=0; i < numOfTok; i++)
data[i] = atoi(tokenArray[i]);
}
At the end of the strtok loop, tokenArray will be set to NULL. You then pass it to custatoi, which presumably crashes when it tries to dereference it.
Note that tokenArray is not an array of strings; it's just a single string pointer (or a pointer to an array of characters). If you want to accumulate the tokens into an array, you'll have to create a separate array for that purpose.
The main problem is that custatoi() expects to work with an array of pointers to char, while tokenArray in main() is a mere pointer to char. The original code never collects all pointers to tokens in the input string into an array that custatoi() expects, there isn't such an array in the original code.
Please study the fixed code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define StrSZE 81
void custatoi(char* tokenArray[], int* data, int numOfTok);
int main(void)
{
char str[StrSZE];
char** tokenArray;
int numOfToken = 0, i;
int* data;
//strInput(str, maxChars);
strcpy(str, "1 345 44 23");
tokenArray = malloc(sizeof(char*));
tokenArray[numOfToken] = strtok(str, " \t");
while (tokenArray[numOfToken] != NULL)
{
printf("token: %s\n", tokenArray[numOfToken]);
numOfToken++;
tokenArray = realloc(tokenArray, sizeof(char*) * (numOfToken + 1));
tokenArray[numOfToken] = strtok(NULL, " \t");
}
data = malloc(numOfToken * sizeof(int));
custatoi(tokenArray, data, numOfToken);
for (i = 0; i < numOfToken; i++)
printf("data[%d]=%d\n", i, data[i]);
return 0;
}
void custatoi(char* tokenArray[], int* data, int numOfTok)
{
int i;
for (i=0; i < numOfTok; i++)
data[i] = atoi(tokenArray[i]);
}
Output (idone):
token: 1
token: 345
token: 44
token: 23
data[0]=1
data[1]=345
data[2]=44
data[3]=23

Resources