I know this question is extremely common and the solution is well-known. But for a long time, I am getting an error I cannot figure out. I am trying to reverse a string in C. My code is given below:
#include <stdio.h>
char *reverse(char *);
int main(void) {
char str[] = "Hello";
char *rev;
rev = reverse(str);
printf("The reversed string is %s", rev);
return 0;
}
char *reverse(char *str){
char *end = str;
char tmp;
if(str){
while(*end){
++end;
}
--end;
while(str < end){
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
return str;
}
As result, I am getting "leH", not "olleH". Can anyone point out why?
The pointer str you return in reverse() does not point to the beginning of the string, but somewhere in the middle at the end of the loop.
Another problem with your function is in case you pass an empty string: end is decremented from the end of the string and points outside the string. This invokes undefined behaviour.
You should use 2 temporary pointers to perform the task:
char *reverse(char *str) {
if (str && *str) {
char *p = str;
char *end = p + strlen(p) - 1;
while (p < end) {
char tmp = *p;
*p++ = *end;
*end-- = tmp;
}
}
return str;
}
Or if you prefer to use index variables:
char *reverse(char *str) {
if (str && *str) {
for (size_t i = 0, j = strlen(str); i < --j; i++) {
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
return str;
}
Because you return the incremented pointer, use another pointer or index notation and it will work, like this
char *reverse(char *str)
{
char *end;
char tmp;
int i;
end = str;
if ((str == NULL) || (*str == '\0'))
return str;
while (*end != 0)
++end;
--end;
i = 0;
while (str + i < end)
{
tmp = str[i];
str[i++] = *end;
*end-- = tmp;
}
return str;
}
When you return str, it's no longer pointing at the beginning of the string.
Another way of achieving reversing string is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse(const char *);
int main(void){
char *s = "hello world";
char *s_rev = reverse(s);
printf("%s => %s", s, s_rev);
free(s_rev);
return 0;
}
char *reverse(const char *s){
char *s_new = strdup(s);
char *s_begptr = &s[0];
char *s_endptr = &s[strlen(s) - 1];
char *ptr = NULL;
for (ptr = s_endptr; ptr >= s_begptr; ptr--, s_new++){
*s_new = *ptr;
}
*s_new = '\0';
s_new -= strlen(s);
return s_new;
}
Notice we are not using any temporary variables to store the value, rather, using both start and end pointers of the same string and using the loop to work backwards from the end of string in reverse.
Related
I am working on a string reversal problem where I am trying to swap values from two ends with one another. As a part of the reverse function, I have a line that checks whether the pointer has reached the end-of-string character (in the form of while(*end!= '\0')). However, this doesn't seem to be working, and at the end of the while loop when I de-reference "end" I get blank. When I use (while(*end)), everything works perfectly but I have to then decrement my pointer "end" to make sure I am accessing the last element of my string. Why can't I check the pointer against the string literal '\0'?
#include<stdio.h>
void reverse(char* s);
void main(){
char str[]="abcdef";
printf("%s\n",str);
reverse(str);
printf("%s\n",str);
}
void reverse(char* p){
char* start = p;
char* end = p;
char tmp;
int length =0;
while(*end!='\0'){
end+=1;
length+=1;
}
printf("%c\n",*end); // problem line
int c;
for (c = 0; c < length/2; c++)
{
tmp = *start;
*start = *end;
*end = tmp;
start++;
end--;
}
//printf("%s\n",p);
}
In the //Problem line the value of *end is '\0' - You should print the integer value of '\0' to verify which is 0 & it works - apart from that you'll need to uncomment the } from reverse function.
'\0' is a non printable character: Reference: Non-printable and Printable ASCII Characters
#include <stdio.h>
#include <string.h>
size_t mystrlen(const char *str)
{
const char *ptr = str;
while(*ptr++);
return ptr - str;
}
char *reverse(char *str)
{
size_t len = mystrlen(str);
char *end = str + len -1;
char *saved = str;
len /= 2;
while(len--)
{
char tmp = *str;
*str++ = *end;
*end-- = tmp;
}
return saved;
}
int main(void)
{
char str[] = "This is the string which will be reversed";
printf("%s\n", reverse(str));
}
your code works. end reaches '\0'. but printf prints string until the first '\0'. so your print appears empty. if you add after the while loop:
--end;
or change the while to: while(*(end+1))
your code will do what you want it to
You don't need the length variable, and you can use pre-decrement on end.
#include <stdio.h>
void reverse(char *start);
int main(void) {
char str[]= "abcdef";
printf("%s\n", str);
reverse(str);
printf("%s\n", str);
}
void reverse(char* start) {
char *end = start;
while(*end != '\0') {
end++;
}
while(start < end) {
char temp = *--end;
*end = *start;
*start++ = temp;
}
}
I have a small problem.
I have a function that takes in two parameters (two strings). For example:
String1 = "hello"
String2 = "leo"
I need to remove all characters from String2 in String1. In this case, my final result should be: "h". I need to incorporate pointers when doing this! I've got this code so far, but it's only remove "e" from "hello". I don't know why it's not working. If someone has a better or efficient way of doing this, please help!
void rmstr(char str1[], char str2[])
{
//Pointers to traverse two strings
char *p_str1 = &str1[0];
char *p_skip;
int length = (int)strlen(str2);
int i;
while(*p_str1 != '\0')
{
for (i = 0; i < length; i++)
{
if(*p_str1 == str2[i])
{
for(p_skip = p_str1; *p_skip == str2[i]; ++p_skip);
memcpy(p_str1, p_skip, &str1[strlen(str1)+1] - p_skip);
}
if(*p_str1 != '\0')
{
++p_str1;
}
}
}
}
char* rmstr(char *str1, char *str2, char *ans) {
char *p1 = str1;
char *p2 = str2;
char *res = ans;
while (*p1 != '\0') {
p2 = str2;
while (*p2 != '\0') {
if (*p1 == *p2) // A character in str1 is found inside str2
break;
p2++;
}
if (*p2 == '\0') { // No match found
*ans = *p1;
ans++;
}
p1++;
}
*ans = '\0';
return res;
}
Testing code:
int main(void) {
char str1[] = "hello";
char str2[] = "elo";
char ans[10];
printf(rmstr(str1, str2, ans));
return 0;
}
Well, this answer has less variables and maybe easier to read.
#include "stdio.h"
/* check if c belongs to the second str */
int char_belong_to_str(char c, char *str)
{
while(*str)
if (c == *str++)
return 1;
return 0;
}
void rmstr(char str1[], char str2[])
{
int result_len = 0; /* saves the result str len*/
char * p_new = str1;
while (*str1)
{
char c = *str1;
if (!char_belong_to_str(c, str2)) /* if not found in str2, save it*/
{
*(p_new + result_len) = c;
++result_len;
}
++str1;
}
*(p_new+result_len) = '\0';
printf("%s \n", p_new);
}
int main()
{
char p1[] = "hello";
char p2[] = "elo";
rmstr(p1, p2);
return 0;
}
I'm new to C programming. I have a task to do.
User inputs two strings. What I need to do is to create a new string that will consist only from common letters of those two given strings.
For example:
if given:
str1 = "ABCDZ"
str2 = "ADXYZ"
the new string will look like: "ADZ".
I can't make it work. I think there must be a better (more simple) algorithm but I have waisted too much time for this one so I want to complete it .. need your help!
what I've done so far is this:
char* commonChars (char* str1, char* str2)
{
char *ptr, *qtr, *arr, *tmp, *ch1, *ch2;
int counter = 1;
ch1 = str1;
ch2 = str2;
arr = (char*) malloc ((strlen(str1)+strlen(str2)+1)*(sizeof(char))); //creating dynamic array
strcpy(arr, str1);
strcat(arr,str2);
for (ptr = arr; ptr < arr + strlen(arr); ptr++)
{
for (qtr = arr; qtr < arr + strlen(arr); qtr++) // count for each char how many times is appears
{
if (*qtr == *ptr && qtr != ptr)
{
counter++;
tmp = qtr;
}
}
if (counter > 1)
{
for (qtr = tmp; *qtr; qtr++) //removing duplicate characters
*(qtr) = *(qtr+1);
}
counter = 1;
}
sortArray(arr, strlen(arr)); // sorting the string in alphabetical order
qtr = arr;
for (ptr = arr; ptr < arr + strlen(arr); ptr++, ch1++, ch2++) //checking if a letter appears in both strings and if at least one of them doesn't contain this letter - remove it
{
for (qtr = ptr; *qtr; qtr++)
{
if (*qtr != *ch1 || *qtr != *ch2)
*qtr = *(qtr+1);
}
}
}
Don't know how to finish this code .. i would be thankful for any suggestion!
The output array cannot be longer that the shorter of the two input arrays.
You can use strchr().
char * common (const char *in1, const char *in2) {
char *out;
char *p;
if (strlen(in2) < strlen(in1)) {
const char *t = in2;
in2 = in1;
in1 = t;
}
out = malloc(strlen(in2)+1);
p = out;
while (*in1) {
if (strchr(in2, *in1)) *p++ = *in1;
++in1;
}
*p = '\0';
return out;
}
This has O(NxM) performance, where N and M are the lengths of the input strings. Because your input is alphabetical and unique, you can achieve O(N+M) worst case performance. You apply something that resembles a merge loop.
char * common_linear (const char *in1, const char *in2) {
char *out;
char *p;
if (strlen(in2) < strlen(in1)) {
const char *t = in2;
in2 = in1;
in1 = t;
}
out = malloc(strlen(in2)+1);
p = out;
while (*in1 && *in2) {
if (*in1 < *in2) {
++in1;
continue;
}
if (*in2 < *in1) {
++in2;
continue;
}
*p++ = *in1;
++in1;
++in2;
}
*p = '\0';
return out;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define min(x,y) ((x)<(y)? (x) : (y))
char* commonChars (const char *str1, const char *str2){
//str1, str2 : sorted(asc) and unique
char *ret, *p;
int len1, len2;
len1=strlen(str1);
len2=strlen(str2);
ret = p = malloc((min(len1, len2)+1)*sizeof(char));
while(*str1 && *str2){
if(*str1 < *str2){
++str1;
continue;
}
if(*str1 > *str2){
++str2;
continue;
}
*p++ = *str1++;
++str2;
}
*p ='\0';
return ret;
}
char *deleteChars(const char *str, const char *dellist){
//str, dellist : sorted(asc) and unique
char *ret, *p;
ret = p = malloc((strlen(str)+1)*sizeof(char));
while(*str && *dellist){
if(*str < *dellist){
*p++=*str++;
continue;
}
if(*str > *dellist){
++dellist;
continue;
}
++str;
++dellist;
}
if(!*dellist)
while(*str)
*p++=*str++;
*p ='\0';
return ret;
}
int main(void){
const char *str1 = "ABCDXYZ";
const char *str2 = "ABCDZ";
const char *str3 = "ADXYZ";
char *common2and3;
char *withoutcommon;
common2and3 = commonChars(str2, str3);
//printf("%s\n", common2and3);//ADZ
withoutcommon = deleteChars(str1, common2and3);
printf("%s\n", withoutcommon);//BCXY
free(common2and3);
free(withoutcommon);
return 0;
}
I will do something like this :
char* commonChars(char* str1, char* str2) {
char* ret = malloc(strlen(str1) * sizeof(char));
int i = j = k = 0;
for (; str1[i] != '\n'; i++, j++) {
if (str1[i] == str2[j]) {
ret[k] = str1[i];
k++;
}
}
ret[k] = '\0';
ret = realloc(ret, k);
return ret;
}
It's been a while i didn't do C, hope this is correct
You can use strpbrk() function, to do this job cleanly.
const char * strpbrk ( const char * str1, const char * str2 );
char * strpbrk ( char * str1, const char * str2 );
Locate characters in string
Returns a pointer to the first occurrence in str1 of any of the characters that are part of str2, or a null pointer if there are no matches.
The search does not include the terminating null-characters of either strings, but ends there.
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "ABCDZ";
char key[] = "ADXYZ";
char *newString = malloc(sizeof(str)+sizeof(key));
memset(newString, 0x00, sizeof(newString));
char * pch;
pch = strpbrk (str, key);
int i=0;
while (pch != NULL)
{
*(newString+i) = *pch;
pch = strpbrk (pch+1,key);
i++;
}
printf ("%s", newString);
return 0;
}
Sorry for the weird use of char arrays, was just trying to get it done fast. The idea behind the algorithm should be obvious, you can modify some of the types, loop ending conditions, remove the C++ elements, etc for your purposes. It's the idea behind the code that's important.
#include <queue>
#include <string>
#include <iostream>
using namespace std;
bool isCharPresent(char* str, char c) {
do {
if(c == *str) return true;
} while(*(str++));
return false;
}
int main ()
{
char str1[] = {'h', 'i', 't', 'h', 'e', 'r', 'e', '\0'};
char str2[] = {'a', 'h', 'i', '\0'};
string result = "";
char* charIt = &str1[0];
do {
if(isCharPresent(str2, *charIt))
result += *charIt;
} while(*(charIt++));
cout << result << endl; //hih is the result. Minor modifications if dupes are bad.
}
So i found the solution for my problem. Eventually I used another algorithm which, as turned out, is very similar to what #BLUEPIXY and #user315052 have suggested. Thanks everyone who tried to help! Very nice and useful web source!
Here is my code. Someone who'll find it useful can use it.
Note:
(1) str1 & str2 should be sorted alphabetically;
(2) each character should appear only once in each given strings;
char* commonChars (char* str1, char* str2)
{
char *ptr, *arr,*ch1, *ch2;
int counter = 0;
for (ch1 = str1; *ch1; ch1++)
{
for(ch2 = str2; *ch2; ch2++)
{
if (*ch1 == *ch2)
counter++;
}
}
arr = (char*)malloc ((counter+1) * sizeof(char));
ch1 = str1;
ch2 = str2;
ptr = arr;
for (ch1 = str1; *ch1; ch1++,ch2++)
{
while (*ch1 < *ch2)
{
ch1++;
}
while (*ch1 > *ch2)
{
ch2++;
}
if (*ch1 == *ch2)
{
*ptr = *ch1;
ptr++;
}
}
if (ptr = arr + counter)
*ptr = '\0';
return arr;
}
I have a problem with my code below, I am trying to reverse a string, but I have run time error, anyone who can help me check it? The problem is:
eg:
INPUT: char *s = "This is my string"
OUTPUT: "string my is This"
#include <iostream>
using namespace std;
void reverse(char *str, int start, int end){
char tmp;
while(end > start){
tmp = str[end];
str[end] = str[start];
str[start] = tmp;
end--;
start++;
}
}
int main()
{
char *s = "This is my string";
int len = strlen(s);
int start = 0;
int end = len-1;
reverse(s, start, end);
printf("%s", s);
end = 0;
while( end < len){
if(s[end] == ' '||s[end] =='\0'){
while(s[start]==' ')
start++;
reverse(s,start,end-1);
start = end;
}
end++;
}
printf("%s", s);
cin.get();
}
You cannot modify this string:
char *s = "This is my string";
You've declared it incorrectly, it should be
const char* = "This is my string";
Normally these strings are allocated in a region of memory which you cannot write to. You should create another buffer to write the reversed string to.
There is a string
char *message = "hello#world#####.......";
How to delete all the "#" and return "helloworld" ?
In Ruby I can use gsub to deal with it
In C, you have to do it yourself. For example:
#include <string.h>
char *remove_all(const char *source, char c)
{
char *result = (char *) malloc(strlen(source) + 1);
char *r = result;
while (*source != '\0')
{
if (*source != c)
*r++ = *source;
source++;
}
*r = '\0';
return result;
}
Note that in that implementation, the caller would have to free the result string.
I believe there is a better algorithm to do this....no freeing is necessary - it's in-place.
char *remove_all(char *string, char c)
{
int idx = 0;
char *beg = string;
while(*string) {
if (*string != c)
beg[idx++] = *string;
++string;
}
beg[idx] = 0;
return beg;
}