my own strcat function using C errors - c

I'm basically coding my very own string functions in C.
I've been trying to do the strcat function using pointers and cannot seem to understand whether I should be allocating memory using malloc or leaving it up to the heap.
char *my_strcat(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;
unsigned char *string;
//string = malloc(strlen(s1) + strlen(s2) + 1);
while (*p1 != '\0')
{
*string = *p1;
string++;
p1++;
if(*p1 == '\0')
{
while(*p2 != '\0')
{
*string = *p2;
string++;
p2++;
}
}
}
return (char *)string;
}
Any tips on more efficiently performing this task or things I'm doing wrong would be great!
Cheers
EDIT
OK so I got a working solution but just wondering after I use malloc where should I free() it?
char *my_strcat(const char *s1, const char *s2)
{
const unsigned char *p1 = (const unsigned char *)s1;
const unsigned char *p2 = (const unsigned char *)s2;
char *string = malloc(sizeof(char *));
char *res = string;
while (*p1 != '\0')
{
*string = *p1;
string++;
p1++;
}
while (*p2 != '\0')
{
*string = *p2;
string++;
p2++;
}
*string = '\0';
return (char *)res;
}

First, I assume that the allocation is commented out by mistake.
You need to save the pointer that you allocate, and return it. Otherwise, you're returning a pointer string, which points at the end of the concatenation result
You are not terminating the resultant string; you need to add *string = '\0'
You should move the second loop to the outside of the first loop, and drop the if condition around it: if the first loop has terminated, you know that *p1 points to \0
char *string = malloc(strlen(s1) + strlen(s2) + 1);
char *res = string;
for (; *p1 ; *string++ = *p1++);
for (; *p2 ; *string++ = *p2++);
*string = '\0';
return res;

strcat doesn't allocate any memory so if you're trying to accomplish the same thing then you don't need to use malloc.
char* strcat(char* destination,char* source) {
int c = 0;
int sc;
while(destination[c] != 0) { c++; }
for(sc = 0;sc < strlen(source);sc++) {
destination[sc+c] = source[sc];
}
destination[sc+c] = 0;
return destination;
}

This worked for me.
char* my_strcat(char* a,char* b)
{
int i,j;
for(i=0;a[i];i++);
for(j=0;b[j];j++,i++)
a[i]=b[j];
a[i]='\0';
}

Related

C function to compare last elements of a string to another using pointers

My problem is to see if str1 ends with the contents of str2.
I tried this:
int string_ends_with(const char *str1, const char *str2) {
int len;
len = strlen(str2);
while ((*str1 == '\0' - len) && *str1 != '\0') {
if (strcmp(str1, str2) == 0) {
return 1;
} else {
return 0;
}
}
}
int main() {
char str[10] = "banana";
char str1[5] = "ana";
string_ends_with(str, str1);
return 0;
}
What I am doing wrong?
This problem needs to be solved only using pointers.
This condition in the while statement
while((*str1 == '\0' - len) && *str1 != '\0')
does not make sense. What does '\0' - len mean ?
You could write the function the following way
int string_ends_with(const char *str1, const char *str2)
{
size_t n1 = strlen( str1 );
size_t n2 = strlen( str2 );
return n2 <= n1 && strcmp( str1 + n1 - n2, str2 ) == 0;
}
If you may not use standard functions then you can write the function the following way
int string_ends_with(const char *str1, const char *str2)
{
const char *p1 = str1;
const char *p2 = str2;
while ( *p1 ) ++p1;
while ( *p2 ) ++p2;
while ( p1 != str1 && p2 != str2 && *p1 == *p2 ) --p1, --p2;
return p2 == str2 && *p1 == *p2;
}
This will be useful if you want to know which string has a greater/lesser value.
int string_ends_with(char *p1, char *p2)
{
char *q1;
char *q2;
if (! p1 || ! p2)
return something;
(p1 + (strlen(p1) - 1));
(p2 + (strlen(p2) - 1));
while (q1 >= p1 && q2 >= p2) {
if (*q2 < *q1) return -1;
else if (*q2 > *q1) return 1;
q1--; q2--;
}
return 0;
}
EDIT: Of course do basic error checking, i'd presume that's a given for most and prefer not to clutter my meagre offering with un-necessary code with regards to a simple example. Still, don't want to ruffle any feathers.
Alright.
You initial test is incorrect, as noted in the other answers.
Here is a slightly smaller and potentially more efficient version:
int string_ends_with(const char *str1, const char *str2) {
const char *p1 = str1;
const char *p2 = str2;
while (*p1) p1++; // same as p1 += strlen(p1);
while (*p2) p2++; // same as p2 += strlen(p2);
while (p2 != str2) {
if (p1 == str1 || *--p1 != *--p2)
return 0;
}
return 1;
}
Note that your main test function should output something and perform more tests:
void test(const char *a, const char *b) {
printf("\"%s\" ends with \"%s\": %s\n",
a, b, string_ends_with(a, b) ? "yes" : "no");
}
int main(void) {
char str[] = "banana";
char str1[] = "ana";
test(str, str1);
test(str1, str);
test(str, str);
test(str, "");
test("", str);
test("", "");
return 0;
}

Error in reversing string

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.

Removing all occurences of all charactesr from second string in first string

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;
}

Create a new string that will consist of common letters from other two strings

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;
}

How to delete special char in C?

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;
}

Resources