Recursively reversing a string in C? - c

I have to reverse a string in a recursive function, but I cannot use loops or strlen to find where the end of the string is. Then I have to pass the reversed string back to main and copy it to a new file. Here's what I have so far:
int reverse(char *str, char *strnew, int p)
{
char temp=str[p];
if(temp=='\0' || temp=='\n')
{
strnew=str;
return p;
}
else
{
reverse(str++, strnew, ++p);
p--;
strnew[p]=str[p];
printf("strnew: %c\n", strnew[p]);
return 0;
}
}
int main(int argc, char *argv[])
{
FILE *fp;
char buffer[100];
char newstr[100];
int pointer=0;
fp=fopen("lab8.txt", "r");
if(fp==NULL)
{
printf("Error opening file\n");
return 0;
}
(fgets(buffer, 100, fp));
reverse(buffer, newstr, pointer);
printf("newstr: %s\n", newstr);
FILE *fp2=fopen("lab8.2.txt", "w");
fputs(newstr, fp2);
fclose(fp);
fclose(fp2);
return 0;
}
I cannot wrap my head around how to reverse the string. I've found where the null character is using p, but how do I copy the string backwards onto a new string?

#include <stdio.h>
int reverse(char *str, int pos){
char ch = str[pos];
return (ch == '\0')? 0 : ((str[pos=reverse(str, ++pos)]=ch), ++pos);
}
int main(){
char buffer[100];
scanf("%99[^\n]", buffer);
reverse(buffer, 0);
fprintf(stdout, "%s\n", buffer);
return 0;
}

Since this is obviously homework, no complete solution, only ideas.
First, you don't need to limit yourself to one recursive function. You can have several, and a resursive implementation of strlen is trivial enough. my_strlen(char *p) evaluates to 0 if *p = 0, and to 1 + my_strlen(p+1) otherwise.
You can probably do it in a single recursion loop, too, but you don't have to.
One more thing: as you recurse, you can run your code both on the front end of recursion and on the back end. A recursion is like a loop; but after the nested call to self returns, you have a chance to perform another loop, this one backwards. See if you can leverage that.

It is quite simple. When you enter the string, you save the character at the position you are are. Call the method recursively more character to the right. When you get to the end of the string, you will have N stack frames, each holding one character of an N character string. As you return, write the characters back out, but increment the pointer as you return, so that the characters are written in the opposite order.

I'll try to be nice and give you a little sample code. With some explanation.
The beauty of recursion is that you don't need to know the length of the string, however the string must be null terminated. Otherwise you can add a parameter for the string length.
What you need to think is that the last input character is your first output character, therefore you can recurse all the way to the end until you hit the end of the string. As soon as you hit the end of the string you start appending the current character to the output string (initially set to nulls) and returning control to the caller which will subsequently append the previous character to the output string.
void reverse(char *input, char *output) {
int i;
if(*input) /* Checks if end of string */
reverse(input+1,output); /* keep recursing */
for(i=0;output[i];i++); /* set i to point to the location of null terminator */
output[i]=*input; /* Append the current character */
output[i+1]=0; /* Append null terminator */
} /* end of reverse function and return control to caller */
Finally, lets test the function.
int main(argc, argv) {
char a[]="hello world";
char b[12]="\0";
reverse(a,b);
printf("The string '%s' in reverse is '%s'\n", a, b);
}
Output
The string 'hello world' in reverse is 'dlrow olleh'

Related

Creating a new string of characters by copying them from an existing string and returning the new string in a "results" array?

im asking the user to enter a string say "Investments". Then it asks the user to enter two space separated integers for "start" and "count". What the code does is it sends those inputs to a function called GetSubstring and GetSubstring takes the source string "Investments", and starts at the string designated by the "start" input, and then counts up to the amount of characters in the "count" input and takes what was iterated and saves that in the result array and sends it back to the main function to be printed out. So if i enter "Investments" for the string, 2 for "start", and 4 for "Count". It would return "vest" in the results array.
My problem is in GetSubstring function in the second while loop, maybe a while loop is the wrong approach or im using the pointers in the wrong way, but the first loop cuts out the unwanted original characters and then im trying to start at that new "source" in the second loop and then count and pull out the string based off the number set in "count". I then append a null operator at the end of that new string and send it back via return.
I am new to C, so any help would be greatly appreciated. Thanks in advance. Below is the code:
Main Function:
#include <stdio.h>
#include <string.h>
#define STR_SIZE 256
//Function Declarations
char *GetSubstring(const char source[], int start, int count, char result[]);
int main(void)
{
//Create source and result string arrays
char source[STR_SIZE];
char result[STR_SIZE];
printf("Please enter any space separated string: ");
//Pull in string and replace the newline character with the null zero
fgets(source, STR_SIZE, stdin);
source[strcspn(source, "\n")] = '\0';
printf("\nPlease enter a space separated start index,"
"and character count: ");
int start;
int count;
//Pull in start index and character count
scanf("%d %d", &start, &count);
//Return extracted string from source string
char ReturnArray = *GetSubstring(source, start, count, result);
//Print results
printf("\"%s\", %d, %d, extracts \"%s\"",
source, start, count, ReturnArray);
return 0;
}
GetSubstring FUNCTION:
#include <stdio.h>
#include <string.h>
//Function Declarations
char *GetSubstring(const char source[], int start, int count, char result[])
{
char ResultCopy = result;
while (source != '\0' && start != 0)
{
source++;
start--;
}
while (source != '\0' && count != 0)
{
*(result++) = *(source++);
count--;
}
ResultCopy = *result += "\0"; //Add null terminator to end of new string
return (ResultCopy);
}
ResultCopy needs to be declared char *, not char, to match result and the return type of the function.
You shouldn't reassign ResultCopy at the end. The whole point of that variable is to remember the original value of result, since you increment that during the copying loop.
You need to assign the character '\0', not a string "\0" to store a null terminator in the result. And just use = rather than +=.
char *GetSubstring(const char source[], int start, int count, char result[])
{
char *ResultCopy = result;
while (source != '\0' && start != 0)
{
source++;
start--;
}
while (source != '\0' && count != 0)
{
*(result++) = *(source++);
count--;
}
*result = '\0'; //Add null terminator to end of new string
return ResultCopy;
}
And in main(), you need to declare the result like this:
char *ReturnArray = GetSubstring(source, start, count, result);
In your code ReturnArray is just a single char, not a string, and it just contained the first character of the result. Then you got undefined behavior when you used a char argument with %s format, which requires a pointer to a string.

C pointer arithmetic array remove chars

I am writing a program that takes a user's comment. Specifically one that has input outside of /* and */ and also inside. I have written my loop to find the char "/" in my array and I am unsure how to remove it and everything in between it until it appears again. For example if my input was "comment /* this is my comment */" I need to remove the /* */ and contents between. So my output would just be "comment". If there is no "/* and */" it doesn't remove anything. I know I need a loop but how would I write a loop that removes chars in the array until the next "/" appears and removes it as well?
My code is as follow:
#include <stdio.h>
#include <string.h>
void remove_comment(char *s1, char *s2){
for(; *s1 != '\0'; s1++){ //loops through array until null value
if(*s1 == '/'){ //if array has '/' stored
//clear array elements till next '/' and removes it as well
}
else{
return; //do nothing to array
}
strcpy(s2,s1); //copies new modified string to s2 for later use
}
int main(){
char s1[101]; //declares arrays up to 100 in length with room for null character
char s2[101];
printf("Enter a comment: "); //enter a comment
fgets(s1, 100, stdin); // saves comment to array
remove_comment(s1,s2); //calls function
printf("%s", s2); //prints my modified array
return 0;
}
Your code seems to build on a loop exploring the chars of the string. I propose you therefore the following solution:
void remove_comment(char *s1, char *s2)
{
for(int in_comment=0; *s1 ; s1++){ //loops through array until null value
if(!in_comment && *s1 == '/' && s1[1]=='*') { //if array has '/' follewed by '*' stored
in_comment=1; // we enter a comment area
s1++;
}
else if (in_comment) { // if we are in a comment area
if (*s1=='*' && s1[1]=='/') { // we only look for end of comment
in_comment = 0;
s1++;
}
}
else *s2++=*s1; // if we're not in comment, in all other cases we just copy current char
}
*s2='\0'; // don't forget to end the string.
}
It uses a in_comment variable to tell if we are currently exploring chars in the comment (and looking for an end of comment) or not (and looking eventually for a start of comment).
It uses *s1 and s1[1] to access the current and the next char.
It leaves the original string unchanged.
Online demo
I know I need a loop
Could use a loop, or use standard library functions. Consider char *strstr(const char *s1, const char *s2); as a candidate part of a solution.
The strstr function locates the first occurrence in the string pointed to by s1 of the sequence of characters (excluding the terminating null character) in the string pointed to
by s2.
The strstr function returns a pointer to the located string, or a null pointer if the string is not found.
Some untested code to give you an idea.
void remove_comment(const char *src, char *dest){
char *start = strstr(str, "/*"); // Look for beginning
if (start) { // Find the beginning?
char *end = strstr(start + 2, "*/"); // Now search 2 past
if (end) { // Find the end?
memcpy(dest, src, start - src);
strcpy(&dest[start - src], end+2);
return;
}
}
strcpy(dest, src);
}
If you want to avoid library funcitons, I'll pass along a hint
// if(*s1 == '/'){
if(s1[0] == '/' && s1[1] == '*') {
Of course this is insufficient for finding /* */ comments in C code like:
puts("/* this is not a C comment, but a string literal */");
int a = '/*', b = '*/';
// start of comment /* xyz */

Better understanding of strstr in C

I already asked on question earlier about the string function strstr, and it just turned out that I had made a stupid mistake. Now again i'm getting unexpected results and can't understand why this is. The code i've written is just a simple test code so that I can understand it better, which takes a text file with a list of 11 words and i'm trying to find where the first word is found within the rest of the words. All i've done is move the text document words into a 2D array of strings, and picked a few out that I know should return a correct value but are instead returning NULL. The first use of strstr returns the correct value but the last 3, which I know include the word chant inside of them, return NULL. If again this is just a stupid mistake I have made I apologize, but any help here on understanding this string function would be great.
The text file goes is formatted like this:
chant
enchant
enchanted
hello
enchanter
enchanting
house
enchantment
enchantress
truck
enchants
And the Code i've written is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE* file1;
char **array;
int i;
char string[12];
char *ptr;
array=(char **)malloc(11*sizeof(char*));
for (i=0;i<11;i++) {
array[i]=(char *)malloc(12*sizeof(char));
}
file1=fopen(argv[1],"r");
for (i=0;i<11;i++) {
fgets(string,12,file1);
strcpy(array[i],string);
}
ptr=strstr(array[1],array[0]);
printf("\nThe two strings chant and %s yield %s",array[1],ptr);
ptr=strstr(array[2],array[0]);
printf("\nThe two strings chant and %s yield %s",array[2],ptr);
ptr=strstr(array[4],array[0]);
printf("\nThe two strings chant and %s yield %s",array[4],ptr);
ptr=strstr(array[5],array[0]);
printf("\nThe two strings chant and %s yields %s",array[5],ptr);
return 0;
}
Get rid of the trailing \n after fgets().
for (i=0;i<11;i++) {
fgets(string, sizeof string, file1);
size_t len = strlen(string);
if (len > 0 && string[len-1] == '\n') string[--len] = '\0';
strcpy(array[i], string);
}
char *chomp(char *str){
char *p = strchr(str, '\n');
if(p)
*p = '\0';
return str;
}
...
strcpy(array[i], chomp(string));

find out char's sequences in array

It has been a long time that I have not dealt with arrays in C.
So I need to find multiple string's sequences in char's array
in fact I need them for parsing some command lines
example:
char *myArray=" go where:\"here\" when:\"i dont know ...\";
I need to find out what are the specified parameter when app runs
I have done some functions but the result is weird
void splitString(char *from ,char start ,char end ,char *into)
{
int size=strlen(from);
for(int i=0;i<size;i++)
{
if(from[i]==start)
{
for(int j=i;j<size;j++){
if(from[j]!=end)
into+=from[j];
else
break;
}
}
break;
}
}
and the call
char *into;
char *from="this is #string# i want to look for ";
splitString(from,'#','#',into);
result in the following dialog
i think you have to terminate into string when the data is received. and just increment j to i+1
void splitString(char *from ,char start ,char end ,char *into)
{
int k = 0;
int size=strlen(from);
for(int i=0;i<size;i++)
{
if(from[i]==start)
{
for(int j=i+1, k = 0;j<size;j++, k++){
if(from[j]!=end)
into[k]=from[j];
else
break;
}
}
break;
}
into[k] = '\0';
}
You have three main problems with your code.
The first is that the line
into+=from[j];
doesn't copy the character, it increases the local pointer. See the answer from kTekkie how to solve that. The second is that you don't terminate the string you copy to, which is also in the answer from kTekkie.
The third major problem is that you don't allocate memory for the into variable, so when you start to properly copy characters, you will copy into whatever into points to, which will be a random memory location. This is undefined behavior and will most likely cause your program to crash. To solve this either create into as an array like
char into[SOME_SIZE];
or to dynamically allocate memory on the heap with malloc
char *into = malloc(SOME_SIZE);
If you go for the dynamic allocation, remember to free the allocated memory when you don't need it any more.
Edit: Taking a close look at the function...
There are a few other problems with your function, besides the ones described above in my answer. One is that you have a break statement in the outer loop, so it will step out of the loop immediately.
I would actually write it something like this:
void splitString(char *from, char start, char end, char *into)
{
/* Really first we make sure the output string can be printed by terminating it */
*into = '\0';
/* First find the `start` character */
while (*from && *from++ != start)
;
/* Now we are either at the end of the string, or found the character */
if (!*from)
return; /* At end of string, character not found */
/* Copy the string while we don't see the `end` character */
while (*from && *from != end)
*into++ = *from++;
/* Now terminate the output string */
*into = '\0';
}
It works, as can be seen here. The previous link also shows how to call it.
Today's topic: http://www.cplusplus.com/reference/clibrary/cstring/strtok/
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}

Building a basic shell, more specifically using execvp()

In my program I am taking user input and parsing it into a 2d char array. The array is declared as:
char parsedText[10][255] = {{""},{""},{""},{""},{""},
{""},{""},{""},{""},{""}};
and I am using fgets to grab the user input and parsing it with sscanf. This all works as I think it should.
After this I want to pass parsedText into execvp, parsedText[0] should contain the path and if any arguments are supplied then they should be in parsedText[1] thru parsedText[10].
What is wrong with execvp(parsedText[0], parsedText[1])?
One thing probably worth mentioning is that if I only supply a command such as "ls" without any arguments it appears to work just fine.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "308shell.h"
int main( int argc, char *argv[] )
{
char prompt[40] = "308sh";
char text[40] = "";
char parsedText[10][40] = {{""},{""},{""},{""},{""},
{""},{""},{""},{""},{""}};
// Check for arguments to change the prompt.
if(argc >= 3){
if(!(strcmp(argv[1], "-p"))){
strcpy(prompt, argv[2]);
}
}
strcat(prompt, "> ");
while(1){
// Display the prompt.
fputs(prompt, stdout);
fflush(stdout);
// Grab user input and parse it into parsedText.
mygetline(text, sizeof text);
parseInput(text, parsedText);
// Check if the user wants to exit.
if(!(strcmp(parsedText[0], "exit"))){
break;
}
execvp(parsedText[0], parsedText[1]);
printf("%s\n%s\n", parsedText[0], parsedText[1]);
}
return 0;
}
char *mygetline(char *line, int size)
{
if ( fgets(line, size, stdin) )
{
char *newline = strchr(line, '\n'); /* check for trailing '\n' */
if ( newline )
{
*newline = '\0'; /* overwrite the '\n' with a terminating null */
}
}
return line;
}
char *parseInput(char *text, char parsedText[][40]){
char *ptr = text;
char field [ 40 ];
int n;
int count = 0;
while (*ptr != '\0') {
int items_read = sscanf(ptr, "%s%n", field, &n);
strcpy(parsedText[count++], field);
field[0]='\0';
if (items_read == 1)
ptr += n; /* advance the pointer by the number of characters read */
if ( *ptr != ' ' ) {
strcpy(parsedText[count], field);
break; /* didn't find an expected delimiter, done? */
}
++ptr; /* skip the delimiter */
}
}
execvp takes a pointer to a pointer (char **), not a pointer to an array. It's supposed to be a pointer to the first element of an array of char * pointers, terminated by a null pointer.
Edit: Here's one (not very good) way to make an array of pointers suitable for execvp:
char argbuf[10][256] = {{0}};
char *args[10] = { argbuf[0], argbuf[1], argbuf[2], /* ... */ };
Of course in the real world your arguments probably come from a command line string the user entered, and they probably have at least one character (e.g. a space) between them, so a much better approach would be to either modify the original string in-place, or make a duplicate of it and then modify the duplicate, adding null terminators after each argument and setting up args[i] to point to the right offset into the string.
You could instead do a lot of dynamic allocation (malloc) every step of the way, but then you have to write code to handle every possible point of failure. :-)

Resources