C - Recursively reverse string from one file into another file - c

I'm trying to reverse a string from a text file using recursion into another text file. The reversed string will be stored in a char array, and buffer will become that array. buffer will then be fprintf-ed to the new file. This is what I have so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
reverse(char *ch, char *str) //receives "buffer" as argument. str traverses ch
{
char array[20]; //will store the reversed string
if(*str == '\0')
return 0; //arrived at end of string
return(reverse(ch, str+1) + 1); //don't know if this is correct
}
//I want to use the returned number as the index number. For example, if I have
//string "abcd", string[0]='d', string[1]='c', string[2]='b', string[3]='a'. Problem is,
//how do I do it?
int main(int argc, char *argv[]) //argv[1] is input file. argv[2] is output file printed backwards
{
FILE *fp1, *fp2;
char *p, buffer[20]; //p points to buffer
fp1 = fopen("a.txt", "r");
if(fp1 == NULL)
{
printf("The file does not exist.\n");
return 0;
}
p = buffer;
while(fgets(buffer, 20, fp1) != NULL) //reads the first 20 characters of file.txt into buffer
{
reverse(buffer, p); //passes "buffer" as argument
fprintf(fp2, "%s\n", buffer);
}
printf("File %s has been successfully reversed into file %s!\n", argv[1], argv[2]);
fclose(fp1);
fclose(fp2);
return 0;
}
Since I am new to recursion, I only have the faintest idea of how to implement my reverse function.

Reversing a string is easier and faster via an iterative loop, but to make a recursive function you could have the function reverse the starting and ending chars, then repeat the process with the smaller string
abcde
^ ^ first call
^ ^ next call
^ end
---
void reverse(char *s, char *e) {
char tmp = *s;
*s++ = *e;
*e-- = tmp;
if (e > s) reverse (s, e);
}
Where s points to the 1st char and e to the last char. Note that the initial string must have a length > 0 (or a test could be added to the function).
Exemple
int main () {
char x[] = "abcde";
reverse(x, x+strlen(x)-1);
printf("%s\n", x);
return 0;
}
outputs edcba.

Related

Trouble with reversing an array while reading input from a file in C

I am currently trying to work on a program that will read in a file line by line and place the content in an array. Then trying to reverse the original array into a second array so I can later compare the two arrays. My current code is
#include <stdio.h>
#include <string.h>
void reversing(char buffer[], char reverse[], int stringLength);
int main(int argc, char const *argv[])
{
int stringLength = 0;
FILE *fp; //Declaring a FILE type pointer calling it fp
char buffer[64]; //Declaring a char array the size of 64 named buffer
fp = fopen("./test.txt", "r");
if(fp == NULL)
{
printf("File did not open!\n");
}
else
{
while(fgets(buffer, 64, (FILE*)fp) != NULL)
{
printf("\nNormal String: %s", buffer); //Print content in buffer(original array)
stringLength = strlen(buffer); //Storing the length of the readed input
char reverse[stringLength]; //Creating array for reversed comparision(comparision not implemented yet)
printf("String length: %d\n", stringLength); //Print string length(for debugging)
reversing(buffer, reverse, stringLength);
printf("Reversed String: %s\n", reverse);//Print content in reverse(Reverse array)
}
printf("\n\nEND OF FILE Reached!\n");
fclose(fp);
}
return 0;
}
void reversing(char buffer[], char reverse[], int stringLength)
{
int i = 0;
int j = stringLength - 1;
while(i < j)
{
reverse[j] = buffer[i];
i++;
j--;
}
}
My test file is simply
A
AB
ABC
ABCD
ABCDE
It should print to the screen
Normal String: A
Reversed String: A
Normal String: AB
Reversed String: BA
Normal String: ABC
Reversed String: CBA
Normal String: ABCD
Reversed String: DCBA
Normal String: ABCDE
Reversed String: EDCBA
When I run the program through a debugger it shows that once inside the reversing function the letters are being swap correctly; however, once it exits the function and the call to print the reversed array is made it is printing garbage, but inside the garbage are the first two elements swap correctly. Any help of suggestion would be greatly appreciated.
As a side note I am trying to make this as simple as possible since the true objective or this program is to take it and implement it in assembly on a ci20 machine.
stringLength = strlen(buffer); //Storing the length of the readed input
char reverse[stringLength]; //Creating array for reversed comparision(comparision not implemented yet)
You don't have enough space to store the trailing \0
char reverse[stringLength];
should be
char reverse[stringLength + 1];
And don't forget to add this traling \0 at the very end in your reverse function:
reverse[stringLength] = '\0';
But notice that (in this case) you don't need a temporary to reverse the string, just pass the original one and swap until the NUL character is reached, take a look to How do you reverse a string in place in C or C++?
Your problem lies in the line while (i < j) in your reversing function. i will end up being less than j when only half of your array will be reversed. Instead, it should be while (i < stringLength)
You should also change your character array char reverse[stringLength] to char reverse[stringLength + 1] so you have space for the '\0' terminating character, which you should add to the array at the end of your reversing function.
It should look like this:
void reversing(char buffer[], char reverse[], int stringLength)
{
int i = 0;
int j = stringLength - 1;
while(i < stringLength)
{
reverse[j] = buffer[i];
i++;
j--;
}
reverse[i] = '\0';
}
Also note that the read function for the file is also reading in a newline character and the reversing function is placing it at the beginning of your reversed string, so output looks like this:
Normal String: A
String length: 2
Reversed String:
A
Normal String: AB
String length: 3
Reversed String:
BA
Normal String: ABC
String length: 4
Reversed String:
CBA
Normal String: ABCD
String length: 5
Reversed String:
DCBA
Normal String: ABCDE
String length: 6
Reversed String:
EDCBA
END OF FILE Reached!
I'll leave it up to you to figure out removing the newline character before sending it to the reversing function. If you can't figure it out, just comment it under this answer and I'll edit the answer.
If you are looking for a really simple solution, you can use strrev from the string.h library. It reverses the string for you, which means you don't have to make your own string reversing function. You can just call it instead.
Something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSIZE 64
int
main(void) {
FILE *filename;
char buffer[BUFFSIZE];
int length;
filename = fopen("test.txt", "r");
if (filename == NULL) {
fprintf(stderr, "%s\n", "Error Reading File!");
exit(EXIT_FAILURE);
}
while (fgets(buffer, BUFFSIZE, filename) != NULL) {
length = strlen(buffer)-1;
if (buffer[length] == '\n') {
buffer[length] = '\0';
}
printf("Normal String: %s\n", buffer);
printf("Reversed String: %s\n", strrev(buffer));
}
return 0;
}
In order to solve my problems reversing the array and forgetting about the '\0', not allowing enough space for the '\0', and dealing with fgets adding a newline. Here is my current code that runs correctly.
#include <stdio.h>
#include <string.h>
void reversing(char buffer[], char reverse[], int stringLength);
int main(int argc, char const *argv[])
{
int stringLength = 0;
FILE *fp; //Declaring a FILE type pointer calling it fp
char buffer[64]; //Declaring a char array the size of 64 named buffer
fp = fopen("./test.txt", "r");
if (fp == NULL)
{
printf("File did not open\n");
return 0;
}
else
{
while(fgets(buffer, 64, (FILE*)fp) != NULL)
{
printf("\nNormal String: %s", buffer); //Print content in buffer(original array)
stringLength = strlen(buffer); //Storing the length of read input
char reverse[stringLength + 1];
reversing(buffer, reverse, stringLength);
printf("Reversed String: %s\n", reverse);//Print content in reverse(Reverse array)
}
printf("\nEND OF FILE Reached!\n");
}
fclose(fp);
return 0;
}
void reversing(char buffer[], char reverse[], int stringLength)
{
int i = 0;
int j = stringLength - 1;
while(i < stringLength)
{
reverse[j] = buffer[i]; //Swap elements
i++;
j--;
}
reverse[i] = '\0'; //Add null terminating
i = 0;
if(reverse[0] == '\n') //If first element is '\n' swift elements
{
while(i < stringLength)
{
reverse[i] = reverse[i + 1];
i++;
}
}
}
It now prints to the screen
Normal String: A
Reversed String: A
Normal String: AB
Reversed String: BA
Normal String: ABC
Reversed String: CBA
Normal String: ABCD
Reversed String: DCBA
Normal String: ABCDE
Reversed String: EDCBA
END OF FILE Reached!
Thank you #PhantomWhiskers and everyone that commented and provided possible solutions to my original question.

Find N letter words in file

I have a problem, my program in C have to find words with N letters, count them and sort them in lexicographical order and save them to an another file. I've done the first 2 things, but sorting them and save to the file doesn't work. It saves only the last word to the second file... do you have any idea why?
this is my code:
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <stddef.h>
#include <string.h>
int main()
{
FILE *r, *fp;
char ch[100];
int n,i,j,x=0;
r=fopen("text.txt","r");
fgets(ch, 100, r);
char *s = ch;
char *p = s;
printf("Give the length of word: ");
scanf("%d",&n);
printf("\n\nWords with %d letters: \n\n",n);
while (*p) {
char *start;
int len;
while (*p && isspace(*p))
++p;
start = p;
while (*p && !isspace(*p))
++p;
len = p - start;
fp=fopen("text2.txt","w");
if (len == n) {
printf("%.*s\n", len, start);
x++;
fprintf(fp,"%.*s",len, start);
}
}
printf("\nNumber of words: %d ",x);
fclose(fp);
getch();
fclose(r);
}
my input file:
hi my name is Zsolt this program if for displaying words with N letters count them and sort them alphabeticaly a save them to an another file
It is because you open text2.txt in every iteration of your while loop. And what is more, you open it with mode "w" which if you look at the documentation states:
write: Create an empty file for output operations. If a file with the same name already exists, its contents are discarded and the file is treated as a new empty file.
So what is happening is, at every iteration, you open the file, discarding whatever was there before, (which after the first iteration would be a file with a single word in it).
Instead you should open it before you enter the while loop.
Additionally, you stated that you wanted to sort the words you found in lexicographical order before you wrote them to the new file. If your code had written the words as you had intended, then they would be in the order they appeared in the original file, not lexicographic order. You are better off saving the pointers to the n-length words in an array, sorting that array, and then writing it all in one go to your output file.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_WORDS 100
int
qstrcmp(const void *a, const void *b)
{
const char
*s = *(const char **)a,
*t = *(const char **)b;
return strcmp(s, t);
}
int
main()
{
FILE *input, *output;
input = fopen("text.txt", "r");
// Get length to filter by
unsigned long n;
scanf("%lu", &n);
char *words[MAX_WORDS];
int i = 0;
// Find words of correct length
char buf[100];
while (fscanf(input, "%99s", buf) != EOF) {
// Protect from buffer overflow
if (i >= MAX_WORDS) {
printf("Too many words!");
break;
}
if (strlen(buf) == n) {
words[i++] = strncpy(malloc(n+1), buf, n+1);
}
}
fclose(input);
// Sort in lexicographical order.
qsort(words, i, sizeof(char *), qstrcmp);
// Write to output
output = fopen("text2.txt", "w");
for (int j = 0; j < i; ++j) {
fprintf(output, "%s\n", words[j]);
}
fclose(output);
// Print number found.
printf("Found %d word%s of length %lu.\n", i, i == 1 ? "": "s", n);
return 0;
}
Implementation Notes
Sorting is achieved with qsort from "stdlib.h".
Pay attention to buffer overflows! In this case I just bail, but alternatively, you could re-allocate the memory for the words array.
Remember to copy the null-byte over when saving the word.
qsort passes references to the array elements it's sorting to its comparator function, so it will pass values of type const char **, this is why we need to use the qstrcmp wrapper function.

Why is strcmp not working when I am reading a line from a file using malloc and determining the strings size independently

Alright, I am seriously puzzled.
I used a snippet of code that would open and read a file and store it in dynamic memory. The output is executed in a void function, where the file is given line by line. The size of the buffer character array was specified because the number of bytes that each line contains is unknown. I want to compare the string that is read with a user input (given by char *word) to see if the program works or not.
In my mind, the strings can only be the same if both their sizes and their character sequences are equivalent, and the dynamic string size is not the same as the file's string size. By using the counter in the main () loop (i.e. pos), I can determine the correct size of the string being read from the file and pass it on to the void function. In the void handle_line function I copied in the characters from the buffer into char *temp because I know the number of characters that temp needs (i.e. pos) and can therefore initialize its size and copy the contents of the dynamic memory into the char *temp. I proceeded to print out the bytes of the string sizes for line, temp, and word. While char *temp and char *word gave their expected values, char *line was always four bytes. Furthermore, the strcmp() did not give the expected result when H2O was read from the CompoundLib file--this in spite of the fact that I know that their sizes and character sequences are the same.
How can this be? What am I missing??? Many thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void handle_line(char *line, int a) {
char temp[a];
int i=0;
char temp_2[a];
char *word="H2O";
for(i=0;i<=a;i++)
temp[i]=line[i];
temp_2[i]=temp[i];
printf("size of temp= %d\n",sizeof temp_2);
printf("size of word= %d\n",sizeof word);
printf("size of line= %d\n",sizeof line);
if (strcmp(temp_2, word) == 0)
puts("Strings equal");
else
puts("Strings do not equal");
printf("%s\n", line);
printf("%d\n", a);
printf("%s\n",temp);
}
int main(int argc, char *argv[]){
char c[1000];
FILE *fptr;
int size = 1024, pos;
int c;
char *buffer = (char *)malloc(size);
FILE *f = fopen("CompoundLib.txt", "r");
if(f) {
do { // read all lines in file
pos = 0;
do{ // read one line
c = fgetc(f);
if(c != EOF) buffer[pos++] = (char)c;
if(pos >= size - 1) { // increase buffer length - leave room for 0
size *=2; //size = size*2
}
}while(c != EOF && c != '\n');
buffer[pos] = 0;
handle_line(buffer, pos);
} while(c != EOF);
fclose(f);
}
free(buffer);
return 0;
}

Splitting a string in a file into array in c

I'm new to programming,and I have a small problem.
I have a file named questions.txt containing a string of questions, I want to read the string from the file then split it into array with each question having an index, for example a[i] = "Question i" etc.
I did so many tries, but it always ends up reading the last line in the file, when write a loop the program stops working.
This is what i came up with, it's all probably wrong:
char str[200];
char *ptr;
FILE * fp = fopen("questions.txt", "r");
while(fgets(str, 200, fp)!= NULL)
printf("%s", str);
ptr = strtok(str, "\n");
while(ptr != NULL)
{
ptr = strtok(str, "\n");
printf("%s\n", ptr);
ptr = strtok(NULL, "\n");
}
fclose(fp);
The file is:
what is your course?
who is your instructor?
Output i get is:
what is your course?
who is your instructor?
who is your instructor?
I want to read the string from the file then split it into an array with each question having an index...
Let me say, that you don't have a string to split into array.
You should better have a file with a one string of questions like this:
what is your course?:who is your instructor? // `:` is some kind of delimiter
I can suppose that you want to make a vector (one dimensional array) of the file. And in that vector, each element will contain a question from the file. Right?
I can share with you a function from my library I've made at the university. I'll write here a simple program. But it uses delimiters - :, for example. You can modify this function for working without delimiters -- this only depends on you.
In two words, this little program does the following:
// BEFORE: you have a string that ends with a null terminating character.
Question_1_abcbadsad:QUestion_2asasdasd:Question_3sldasdsa\n
^
here ^<< printing 'string' stops
// AFTER: an array of questions. Each of them ends with a null terminating character.
Question_1_abcbadsad\nQUestion_2asasdasd\nQuestion_3sldasdsa\n
^
^<< printing argz[0] will stop here
main.c
#include "argz.h"
int main()
{
error_t func;
char *argz; // pointer to a vector; to an array of questions
size_t argz_len;
// size of that vector (the size of the string you've got from the file)
// Consider `string` to be your `ptr`. You read a string from the file so
// `ptr` will point to the string.
char *string = "Question_1_abcbadsad:QUestion_2asasdasd:Question_3sldasdsa";
// Here `:` is a separate character.
func = argz_create_sep(string, ':', &argz, &argz_len);
if(func == OK)
argz_print(argz, argz_len);
else
printf("ERROR\n");
return 0;
}
argz.c
#include "argz.h"
error_t argz_create_sep (const char *string, int sep, char **argz, size_t *argz_len)
{
int i;
char *ch;
int len = strlen(string);
if(len==0)
return ENOMEM;
*argz = (char*) malloc (sizeof(char)*(len + 1));
strcpy(*argz, string);
*argz_len = strlen(*argz);
ch = *argz;
for(i = 0; i < len; i++) {
if(*ch == sep) *ch='\0';
ch++;
}
return OK;
}
void argz_print(const char *argz, size_t argz_len)
{
const char *ch;
int i;
ch = argz;
for(i = 0; i < argz_len; i++) {
if(*ch == '\0')
printf("\n");
else
printf("%c",*ch);
ch++;
}
printf("\n\n\n");
}
argz.h
#include <stddef.h> // for size_t
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef enum {OK, ENOMEM} error_t;
/* function prototypes */
error_t argz_create_sep (const char *string, int sep, char **argz, size_t *argz_len);
void argz_print (const char *argz, size_t argz_len);
I think what you want is something like this:
#include <stdio.h>
int main(){
int i=0;
char str[200],s='1'; //s is give a random character
FILE * fp = fopen("questions.txt", "r");
while (s!=EOF){ //works until s= the end of file
s=getc(fp); //s starts to receive characters from text file
str[i]=s; //each character of text is placed into the string array
i++;
}
str[i]='\0'; //s reached EOF so lets indicate where we stopped in the string
fclose(fp);
printf("%s\n",str);
//EDIT: changing 1D str to 2D str2
char str2[10][200]; // 10 for max no. of questions, 200 - length of each question
int j=0,k=0;
i=0;
for(j=0;j<200;j++){
str2[i][k]=str[j];
k++;
if (str[j]=='\n'){
i++;
k=0;}
}
for(i=0;i<10;i++) //prints your 2D string array
printf("%s",str2[i]); //after the last question there will be junk
return 0;
}

strstr char array inside struct array

I have a struct defined as;
struct player {
int no, age;
char name[20];
} players[10];
Array is filled from file. What I try to do is, take input from user, add input to char array, send it to search(char lookup[]) function and strstr name field in a loop.
EDİT: Sorry I corrected the order. I'm trying to strstr in a loop.
char *p = strstr(players[x].name, inputFromUser);
but p is always null. How can I do this?
Thanks in advance.
EDIT - Code Added...
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
struct player {
int no, age;
char name[20];
} players[20];
void fillstruct(char *);
void search(char []);
int main(int argc, char *argv[])
{
int arg;
int c;
int d;
int i=0;
char a[100];
char *filename = NULL;
while((arg=getopt(argc, argv, "f:"))!=-1)
{
switch(arg)
{
case 'f':
filename = optarg;
fillstruct(filename);
break;
default:
break;
}
}
while((c=fgetc(stdin))!=EOF)
{
if(c!=10)
{
a[i]=c;
i++;
}
else
{
a[i]='\0';
search(a);
i=0;
}
}
return 0;
}
void search(char a[])
{
int i=0;
int col;
int found=0;
char *p =NULL;
while((i<20)&&(found==0))
{
p = strstr(a, players[i].name);
if(p)
{
col = p-a;
printf("\nPlayer '%s' found in '%s'.. Found index: %d", a, players[i].name, col);
found=1;
}
else
{
printf("\np=%s a=%s player[%d].name=%s", p, a, i, players[i].name);
}
i++;
}
}
void fillstruct(char *name)
{
FILE *fp;
char line[100];
int i=0;
fp = fopen(name, "r");
if(fp==NULL)
{
exit(1);
}
while(fgets(line, 100, fp)!=NULL)
{
players[i].no=i;
strcpy(players[i].name, line);
fprintf(stdout, "\nplayer=%s", players[i].name);
players[i].age=20;
i++;
}
fclose(fp);
}
Added as answer as suggested by mic_e
Assuming you're trying to search for a player name using the input from a user, you have the arguments of strstr in the reverse order. Also note that strstr is case sensitive.
char *p = strstr(players[x].name, inputFromUser);
fgets stores the \n and then stops taking input.
So suppose a player name is "user", players[i].name will be equal to "user\n" while a is "user".
So return of strstr is always NULL.
Try this instead:
p = strstr(players[i].name,a);
OR, remove the \n after taking input from file by fgets:
while(fgets(line, 100, fp)!=NULL)
{
players[i].no=i;
strcpy(players[i].name, line);
players[i].name[strlen(players[i].name)-1]='\0'; //add this line
fprintf(stdout, "\nplayer=%s", players[i].name);
players[i].age=20;
i++;
}
Like this:
char *p = strstr(players[x].name, inputFromUser);
It should work, It's fail if your input is wrong let me expalain in simple
int main()
{
char *ret;
char mystr[]="stack";
char str[]="This is stack over flow string";
ret = strstr(str, mystr);
printf("The substring is: %s\n", ret);
return(0);
}
Output is
The substring is: stack over flow string
That means
This function returns a pointer to the first occurrence in str of any of the entire sequence of characters specified in mystr, or a null pointer if the sequence is not present in str.
It case sensitive function means if try to search like
char mystr[]="Stack";//Note here first char is capital
And you got output like
The substring is: (null)
You can check your input and target string at your side by just printing content of it and verify it's correct or not.
printf("str1:%s str2:%s\n",players[x].name,inputFromUser)
char *p = strstr(players[x].name, inputFromUser);
I hope this clear your doubts.
That Should Work.
I think You have the problem with file reading Which fills the data array.
Please make sure that data you filled into structure is Ok.
And strstr returns address of the first Occurrence of the string1 in string2
where,
strstr(string2, string1);

Resources