Reverse string in C [duplicate] - c

This question already has answers here:
What is going on with 'gets(stdin)' on the site coderbyte?
(3 answers)
Closed 3 years ago.
I just want to reverse the string order by switching the place of each index in the string.
#include <stdio.h>
#include <string.h>
void FirstReverse(char str[]) {
int a = strlen(str);
for(int i=0; i<strlen(str) ;i++){
str[i] = str[a-1];
a-=1;
}
}
int main(void) {
// keep this function call here
FirstReverse(gets(stdin));
return 0;
}
Error: "signal: segmentation fault (core dumped)"

There are multiple errors in your code. The obvious ones are that gets is used wrong (and, to be honest, that it is used at all) and it does not output the result in any way. But let's apply some quick fixes with minimal changes to your logic:
#include <stdio.h>
#include <string.h>
void FirstReverse(char str[]) {
int a = strlen(str);
for(int i=0; i<strlen(str) ;i++){
str[i] = str[a-1];
a-=1;
}
}
int main(void) {
char string[100]; // This is going to be our working field where the changes happen
fgets(string, 100, stdin); // read a line of up to 100 characters into "string"
FirstReverse(string); // do the work (this could be chained, like it was originally)
puts(string); // output the result
return 0;
}
Now it compiles and executes without failing but the result is wrong:
In: My favourite string
Out: gnirts ette string
What went wrong? Let's follow what happens step by step:
i a
↓ ↓
My favourite string
(program writes the last character [see point 3 below] in place of `M`)
↓ ↓
y favourite string
(program writes `g` in place of `y`)
↓ ↓
g favourite string
(program writes `n` in place of the space)
↓ ↓
gnfavourite string
(program writes `i` in place of `f`)
etc.
ia
↓↓
gnirts eite string
(program writes `t` in place of `i`)
ai
↓↓
gnirts ette string
(program writes `t` in place of `t`)
a i
↓ ↓
gnirts ette string
(program writes `e` in place of `e`)
etc.
Three problems here:
By rewriting a character from the start by another from the end, you're not doing swapping. You're just copying the data from the end to start (but surely, in reverse order). The original is lost.
You are actually going twice through, because by the time i reaches half of the interval, a keeps decreasing and they cross. Now i still needs to finish the loop and a continues towards the beginning of the string where you've already been. If you actually did swapping, you'd swap 1 with 2 and then later 2 with 1 again, resulting in the original unchanged!
(minor) A string returned by (f)gets ends with a newline character, so that becomes the beginning of your result. Probably not what you want, but has an easy fix of chopping that off before feeding the string to your function.
You'll need to deal with each of these, other answers by now contain some advice. But I thought it instructive to run your code and try to "think like the machine" in explaining why the computer misunderstands your intention. If you swap the letters by copying one in a temporary variable, then rewriting str[i], then writing back in str[a-1] from the temporary, and stop before i and a cross each other, you can see for yourself you'll take care of 1 and 2.

run only till mid of the string
keep in some var the overridden char in side the loop
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
void FirstReverse(char str[]) {
int a = strlen(str);
for (int i = 0; i <= a; ++i, --a) {
char c = str[i];
str[i] = str[a - 1];
str[a - 1] = c;
}
}
int main(void) {
// keep this function call here
char s[100] = { 0 };
scanf("%s",s);
FirstReverse(s);
printf("%s",s);
return 0;
}

Simple way to do it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * reverse(char *str)
{
size_t size = strlen(str);
char *res = malloc(size * sizeof(char));
for(size_t i=0; i<size; i++) {
res[i] = str[size-i-1];
}
return res;
}
int main(void)
{
printf("%s\n",reverse("Hello World"));
return 0;
}
Output : dlroW olleH
Instead of switching each char, just create a new string in which you copy the last char, then the last-1 and so on. You'll also prevent yourself from switching the same char if the length of your string is uneven ('\0' put aside).

Related

For loop is running too often

I have a for loop which should run 4 times but is running 6 times.
Could you please explain the behaviour?
This is strange because stringarr1 is not changed.
Edit: I want to remove all '!' from my first string and want to save the letters in a second string.
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
char stringarr1[] = "a!bc";
char stringarr2[] = "";
printf("%d\n", strlen(stringarr1)); // lenght --> 4
for (size_t i = 0; i < strlen(stringarr1); i++)
{
printf("i: %d\n", i);
if (stringarr1[i] != '!') {
stringarr2[strlen(stringarr2)] = stringarr1[i];
printf("info: != '!'\n");
}
}
}
You are overrunning the buffer for stringarr2 (length 1), which is in this case corrupting the memory-adjacent stringarr1, causing the string length to change by overwriting its nul terminator.
Then because you are reevaluating the string length on each iteration, the loop will run for a non-deterministic number of iterations - in your case just 6, but it could be worse; the behaviour you have observed is just one of several possibilities - it is undefined.
Apart from correcting the buffer length for stringarr2, it is best practice to evaluate loop-invariants once (although in this case the string length is not invariant due to a bug). So the following:
const size_t length = strlen( stringarr1 ) ;
for( size_t i = 0; i < length; i++ )
{
...
will run for 4 iterations regardless of the buffer overrun bug because the length is not reevaluated following the corruption. Re-evaluating loop-invariants can lead to very slow code execution.
Your code can run any number of times. You write beyond the end of stringarr2 so you may be smashing the stack and overwriting local variables. What you meant to do is probably something like this:
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
char stringarr1[] = "a!bc";
char stringarr2[10];
int len = strlen(stringarr1);
printf("%d\n", len); // lenght --> 4
for (size_t i = 0; i < len; i++)
{
printf("i: %d\n", i);
if (stringarr1[i] != '!') {
stringarr2[len] = stringarr1[i];
printf("info: != '!'\n");
}
}
}
Like others said, it is not really clear what you are trying to accomplish here. But in C, a declaration like char s[] = "string" only allocates enough memory to store whatever is on the right hand side of the assignment. If that is an empty string like in your case, only a single byte is allocated, to store the end of string 'null' character. You need to either explicitly specify, like I did, the number of bytes to allocate as the array size, or use dynamic memory allocation.
The problem is that you're writing past the end of stringarr2. This triggers undefined behaviour.
To fix this, you need to allocate sufficient memory for stringarr2.
First, we must allocate the string to be long enough.
char stringarr1[] = "a!bc";
//save this in a variable beforehand because strlen loops over the string every time it is called
size_t len = strlen(stringarr1);
char stringarr2[1024] = { 0 };
{ 0 } initializes all characters in the string to 0, which means the last one will always be a null terminator after we add characters. This tells C string functions where the string ends.
Now we can put stuff in there. It seems like you're trying to append, so keep a separate iterator for the 2nd string. This is more efficient than calling strlen every loop.
for(size_t i = 0, j = 0; i < len; i++){
printf("i: %d\n", i);
if (stringarr1[i] != '!') {
stringarr2[j++] = stringarr1[i];
printf("info: != '!'\n");
}
}

why string a gets appended to string b in this code

i am writing a basic c program to display two strings, one taken from user i.e "a" and the other being defined in code "b" but when i run the code below string "a" gets appended to "b". why? and what is that symbol at end of "a"
updated code:
#include <stdio.h>
#include <string.h>
int main()
{
char a[ 5 ];
int i=0;
while(i<5)
{
a[i]=getchar();
i++;
}
char b[]={'r','f','s','/0'};
printf("output:-");
printf("\n %s",a);
printf("\n %s",b);
return 0;
console
qwert
output:-qwert$
rfs$qwert$
there is a some special symbol instead of $ above, what is it?
Putting all the comments into an answer. The problems in the original code stem mostly from not NUL terminating the character arrays to produce valid C strings.
a is not NUL terminated. Can fix by increasing the a array by 1 and explicitly writing a NUL to the last byte.
b is not NUL terminated. Can fix by initialising b using a literal string or a char array with '\0' as the last byte. The example below uses the former.
Here is the full code with the errors corrected. Note that the code to read input is fragile as it only accepts exactly a 5 character string.
#include <stdio.h>
#include <string.h>
int main(void)
{
char a[6];
int i=0;
while (i<5) {
a[i]=getchar();
i++;
}
a[i] = '\0';
char b[]="rfs";
printf("output:-\n");
printf(" %s\n",a);
printf(" %s\n",b);
return 0;
}

Concatenating Strings-changing words into pig latin

I keep receiving "Segmentation fault (core dumped)".
How can I swap the first letter of a given word that the user inputs to the end of the word and then add an "ay".
For example:
input "Code"
output "odecay"
#include<stdio.h>
#include<string.h>
int main()
{
char pig[100],p[10],i[100];
int j,length;
printf("What word would you like to change into pig latin");
scanf("%s",pig);
length=strlen(pig);
strcat(p,pig[0]);
for(j=0;j<length;j++)
{
pig[j]=pig[j+1];
}
strcat(pig,p);
strcat(pig,"ay");
printf("%s",pig);
return 0;
}
How can I swap the first letter of a given word that the user inputs to the end of the word and then add an "ay"
Save the first character ("letter")
char c = pig[0];
Move the rest of pig one char to the beginning
memmove(pig, pig + 1, strlen(pig) - 1);
alternativly use this statement
memmove(&pig[0], &pig[1], strlen(pig) - 1);
(Note that memcpy() won't work here as source and destiantion overlap.)
Replace the "old" last character with the "old", stored first character
pig[strlen(pig) - 1] = c;
Append "ay"
strcat(pig, "ay");
Print the result:
printf("%s\n", pig);
There is no need for a second "string", char-array.
Assuming pig is large enough, that is one char larger then the data to be scanned in from the user, one can even ommit the use of the intermediate character `c, as per my sketch above.
Initialise pig to all 0s
char pig[100] = "";
Scan in data
scanf("%98s", pig); /* Add tests for failure reading as needed. */
Append the first character of the input, that is copy it to the end of pig
pig[strlen(pig)] = pig[0];
Move all of pig one character to the beginning
memmove(pig, pig + 1, strlen(pig) - 1);
Print the result:
printf("%s\n", pig);
This code runs but there is a slight problem with your algorithm. Since this is probably homework I'll let you figure that part out.
#include <stdio.h>
#include <string.h>
int main()
{
// These should be initialized before use.
char pig[100] = "",
char p[10] = "";
printf("What word would you like to change into Pig Latin: ");
scanf("%s", pig);
unsigned long length = strlen(pig); // strlen returns an unsigned long
strcat(p, &pig[0]); // This needs a pointer to char
for(int j = 0; j < length; j++)
{
pig[j] = pig[j + 1];
}
strcat(pig, p);
strcat(pig, "ay");
printf("%s", pig);
return 0;
}
Input:
Code
Output:
odeCodeay
As I said, the algorithm is not quite right but now that the code runs you should be able to fix it pretty quick. Also, since you are new to programming notice some of the code formatting which makes it more readable.
EDIT
Since others have already mentioned it, changing the line strcat(p, &pig[0]); to strncat(p, pig, 1); will produce the desired output and still use your original algorithm.
strcat(p,pig[0]); // segmentation fault may happen in this line.
char *strcat(char *dest, const char *src) // takes two string but you are passing pig[0] in the second argument which is char
You can use char *strncat(char *dest, const char *src, size_t n)
Thus the proper way to concat a char to a string would be
strncat(p,&pig[0],1); // where 1 is passed in the third argument
//so that it reads only 1 char i.e. pig[0] and ignore next characters
// otherwise the whole pig string will be concatenated.

Need help finding bug, if string input is composed all of same character one output character is corrupt

reverser() reverses a cstring (not in place). 99% of the time it works but some input corrupts it for example it appears if aStr2[] is assigned a string made up of the same character it will have an error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverser(const char *str);
int main()
{
char aStr[] = "aaa";
char aStr2[] = "cccccc";
printf("%s %s", aStr, aStr2);
char* tmp = reverser(aStr2);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr2);
return 0;
}
char* reverser(const char *str)
{
char* revStr = (char*)malloc(strlen(str));
int i;
for(i = strlen(str)-1; i >= 0; i--)
{
revStr[strlen(str)-1-i] = str[i];
}
return revStr;
}
Gives
aaa cccccc
cccccc9 cccccc
Process returned 0 (0x0) execution time : 0.068 s
Press any key to continue
Notice the 9 that shouldn't be there.
Change this malloc to strlen(str) + 1 , plus 1 for '\0'
char* revStr = (char*)malloc(strlen(str) + 1);
and after the for loop
revStr[strlen(str)+1] = '\0';
Your problem is that you don't put the string terminator in your reversed string. All strings in C are actually one extra character that isn't reported by strlen, and that is the character '\0' (or plain and simple, a zero). This tells all C functions when the string ends.
Therefore you need to allocate space for this extra terminator character in your malloc call, and add it after the last character in the string.
There are also a couple of other problems with your code, the first is that you should not cast the return of malloc (or any other function returning void *). Another that you have a memory leak in that you do not free the memory you allocate. This last point doesn't matter in a small program like the one you have here, but will be an issue in larger and longer running programs.
You haven't null-terminated your reversed string. You need to set the final index of revStr[] to 0.

printf() isn't being executed

I wanted to write a program which counts the occurrences of each letter in a string, then prints one of each letter followed by the count for that letter.
For example:
aabbcccd -
Has 2 a, 2 b, 3 c, and 1 d
So I'd like to convert and print this as:
a2b2c3d1
I wrote code (see below) to perform this count/conversion but for some reason I'm not seeing any output.
#include<stdio.h>
main()
{
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
type=*cp;
cp++;
count=cp;
int c;
for(c=1;*cp==type;c++,cp++);
*count='0'+c;
}
count++;
*count='\0';
printf("%s",array);
}
Can anyone help me understand why I'm not seeing any output from printf()?
char array[]="aabbcccd";
char type,*count,*cp=array;
while(cp!='\0'){
*cp is a pointer it's pointing to the address of the start of the array, it will never be == to a char '\0' so it can't leave the loop.
You need to deference the pointer to get what it's pointing at:
while(*cp != '\0') {
...
Also, you have a ; after your for loop, skipping the contents of it:
for(c=1;*cp==type;c++,cp++); <-- this ; makes it not execute the code beneath it
After fixing both of those problems the code produces an output:
mike#linux-4puc:~> ./a.out
a1b1c2cd
Not the one you wanted yet, but that fixes your problems with "printf not functional"
Incidentally, this code has a few other major problems:
You try to write past the end of the string if the last character appears once (you write a '1' where the trailing '\0' was, and a '\0' one character beyond that.
Your code doesn't work if a character appears more than 9 times ('0' + 10 is ':').
Your code doesn't work if a character appears more than 2 times ("dddd" doesn't become "d4"; it becomes "d4dd").
Probably line-buffering. Add a \n to your printf() formatting string. Also your code is very scary, what happens if there are more than 9 of the same character in a row?
1) error correction
while(*cp!='\0'){
and not
while(cp!='\0'){
2) advice
do not use array[] to put in your result user another array to put in your rusel it's more proper and eay
I tried to solve your question quickly and this is my code:
#include <stdio.h>
#define SIZE 255
int main()
{
char input[SIZE] = "aabbcccd";/*input string*/
char output[SIZE]={'\0'};/*where output string is stored*/
char seen[SIZE]={'\0'};/*store all chars already counted*/
char *ip = input;/*input pointer=ip*/
char *op = output;/*output pointer = op*/
char *sp = seen;/*seen pointer=sp*/
char c,count;
int i,j,done;
i=0;
while(i<SIZE && input[i]!='\0')
{
c=input[i];
//don't count if already searched:
done=0;
j=0;
while(j<SIZE)
{
if(c==seen[j])
{
done=1;
break;
}
j++;
}
if(done==0)
{//if i never searched char 'c':
*sp=c;
sp++;
*sp='\0';
//count how many "c" there are into input array:
count = '0';
j=0;
while(j<SIZE)
{
if(ip[j]==c)
{
count++;
}
j++;
}
*op=c;
op++;
*op=count;
op++;
}
i++;
}
*op='\0';
printf("input: %s\n",input);
printf("output: %s\n",output);
return 0;
}
It's not a good code for several reasons(I don't check arrays size writing new elements, I could stop searches at first empty item, and so on...) but you could think about it as a "start point" and improve it. You could take a look at standard library to copy substring elements and so on(i.e. strncpy).

Resources