Concatenating two string (K&R) - c

I'm trying to mimic a sample program given in K&R, which looks like this:
void strcat(char s[], char t[])
{
int i, j;
i = j = 0;
while (s[i] != '\0') /* find end of s */
i++;
while ((s[i++] = t[j++]) != '\0') /* copy t */
;
}
I want to do the same thing, except that, instead of appening t to s, I'd like to copy both into a new string. My try is as follows :
#include <stdio.h>
#include <string.h>
void concat
(const char lstr[], const char rstr[], char outstr[])
{
int i, j;
i = j = 0;
while (lstr[i] != '\0')
outstr[i++] = lstr[i++];
while ((outstr[i++] = rstr[j++]) != '\0')
;
}
int main(void)
{
char lword[] = "foo";
char rword[] = "bar";
char outword[strlen(lword) + strlen(rword)];
concat(lword, rword, outword);
printf("%s\n", outword);
}
However, the above only prints garbage (I mean f�����bar). I can't find out where the error lies.

Two problems:
No space for terminating null character in outword. Needs to be:
char outword[strlen(lword) + strlen(rword) + 1];
/*^^^*/
This is undefined behaviour as i is being modified twice in the same statement:
outstr[i++] = lstr[i++];
/* Change to: */
while (lstr[i] != '\0')
{
outstr[i] = lstr[i];
++i;
}
With these two changes the program produces a new concatenated string (http://ideone.com/9QbU0q).

Every string in C needs to end with a null character, which won't be visible. It does however need to be accounted for in the size of the memory you allocate.

When copying lstr to outstr you're incrementing your index twice. Use outstr[i] = lstr[i++]

Related

Is there an easy way to remove specific chars from a char*?

char * deleteChars = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r"
I have this and i'm trying to remove any of these from a given char*. I'm not sure how I would go about comparing a char* to it.
For example if the char* is equal to "hello," how would I go about removing that comma with my deleteChars?
So far I have
void removeChar(char*p, char*delim){
char*holder = p;
while(*p){
if(!(*p==*delim++)){
*holder++=*p;
p++;
}
}
*holder = '\0';
A simple one-by-one approach:
You can use strchr to decide if the character is present in the deletion set. You then assign back into the buffer at the next unassigned position, only if not a filtered character.
It might be easier to understand this using two indices, instead of using pointer arithmetic.
#include <stdio.h>
#include <string.h>
void remove_characters(char *from, const char *set)
{
size_t i = 0, j = 0;
while (from[i]) {
if (!strchr(set, from[i]))
from[j++] = from[i];
i++;
}
from[j] = 0;
}
int main(void) {
const char *del = "\"\'.“”‘’?:;-,—*($%)! \t\n\x0A\r";
char buf[] = "hello, world!";
remove_characters(buf, del);
puts(buf);
}
stdout:
hello world
If you've several delimiters/characters to ignore, it's better to use a look-up table.
void remove_chars (char* str, const char* delims)
{
if (!str || !delims) return;
char* ans = str;
int dlt[256] = {0};
while (*delims)
dlt[(unsigned char)*delims++] = 1;
while (*str) {
if (dlt[(unsigned char)*str])
++str; // skip it
else //if (str != ans)
*ans++ = *str++;
}
*ans = '\0';
}
You could do a double loop, but depending on what you want to treat, it might not be ideal. And since you are FOR SURE shrinking the string you don't need to malloc (provided it was already malloced). I'd initialize a table like this.
#include <string.h>
...
char del[256];
memset(del, 0, 256 * sizeof(char));
for (int i = 0; deleteChars[i]; i++) del[deleteChars[i]] = 1;
Then in a function:
void delChars(char *del, char *string) {
int i, offset;
for (i = 0, offset = 0; string[i]; i++) {
string[i - offset] = string[i];
if (del[string[i]]) offset++;
}
string[i - offset] = 0;
}
This will not work on string literals (that you initialize with char* x = "") though because you'd end up writing in program memory, and probably segfault. I'm sure you can tweak it if that's your need. (Just do something like char *newString = malloc(strlen(string) + 1); newString[i - offset] = string[i])
Apply strchr(delim, p[i]) to each element in p[].
Let us take advantage that strchr(delim, 0) always returns a non-NULL pointer to eliminate the the null character test for every interrelation.
void removeChar(char *p, char *delim) {
size_t out = 0;
for (size_t in; /* empty */; in++) {
// p[in] in the delim set?
if (strchr(delim, p[in])) {
if (p[in] == '\0') {
break;
}
} else {
p[out++] = p[in];
}
}
p[out] = '\0';
}
Variation on #Oka good answer.
it is better way - return the string without needless characters
#include <string.h>
char * remove_chars(char * str, const char * delim) {
for ( char * p = strpbrk(str, delim); p; p = strpbrk(p, delim) )
memmove(p, p + 1, strlen(p));
return str;
}

Recreate strrchr() but getting extra characters at the end of string

A task I have is to recreate the function strrchr. I figured out a way to iterate backward from the input given and stopping at the character I need to stop at, but the string came out backwards obviously. I already had created a function to reverse a string so I used that to reverse it back to normal. It works, but somewhere in my while loop when stopping at the character, it adds extra characters. Please help! I don't understand why!
#include <stdio.h>
#include <string.h>
// #include <stddef.h>
int
main () {
char* my_strrchr(char* param_1, char param_2)
{
int i = strlen(param_1) - 1;
int q = 0;
char new[strlen(param_1)];
char *new_ptr = new;
while (i >= 0) {
new[q] = param_1[i];
printf("%c\n", new[q]);
if (param_1[i] == param_2) {
i = 0;
}
i--;
q++;
}
int size = strlen(new_ptr) - 1;
for (int i = 0, q = size; i < q; i++, q--) {
char temp = new_ptr[i];
new_ptr[i] = new_ptr[q];
new_ptr[q] = temp;
}
printf("%s", new_ptr);
return (char *)new_ptr;
}
char *phrase = "C Language is HARD.";
char c = 'g';
my_strrchr(phrase, c);
return 0;
}
You don't need to do anything fancy. Just walk the string from the beginning, updating a variable with the address of the character you're looking for every time it's found, and return it when you hit the end of the string (Unlike strchr(), where you return after the first match). That way you only need one pass through the string instead of the two times it takes if you first find the length and then go backwards.
#include <stdio.h>
#include <stdlib.h>
// Really should return a const char*. Silly standard.
char *my_strrchr(const char *s, int c) {
const char *pos = NULL;
while (*s) {
if ((unsigned char)*s == (unsigned char)c) pos = s;
s++;
}
if (c == 0) {
// If searching for '\0', return a pointer to the one
// at the end of the string
return (char *)s;
} else {
return (char *)pos;
}
}
int main(void){
const char *foo = "the quite wet duck quacks a lot";
puts(my_strrchr(foo, 'q'));
return 0;
}

How can I make a function to remove double letters in C?

I am trying to make a function that removes double letters from a string. The function is only supposed to remove double letters next to each other, not in the whole string. e.g 'aabbaa' would become 'aba' (not 'ab'). Im a fairly new to c programming and dont fully understand pointers etc. and need some help. Below is what I have so far. It does not work at all, and I have no idea what to return since when I try and return string[] it has an error:
char doubleletter( char *string[] ) {
char surname[25];
int i;
for((i = 1) ; string[i] != '\0' ; i++) {
if (string[i] == string[(i-1)]) { //Supposed to compare the ith letter in array with one before
string[i] = '\0' ; //Supposed to swap duplicate chars with null
}
}
surname[25] = string;
return surname ;
Try the following. It is a clear simple and professionally-looked code.:)
#include <stdio.h>
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q ) *++p = *q;
}
return s;
}
int main(void)
{
char s[] = "aabbaa";
puts( unique( s ) );
return 0;
}
The output is
aba
Also the function can be rewritten the following way that to escape unnecassary copying.
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q )
{
( void )( ( ++p != q ) && ( *p = *q ) );
}
}
return s;
}
Or
char * unique( char *s )
{
for ( char *p = s, *q = s; *q++; )
{
if ( *p != *q && ++p != q ) *p = *q;
}
return s;
}
It seems that the last realization is the best.:)
First of all delete those parenthenses aroung i = 1 in for loop (why you put them there in the first place ?
Secondly if you put \0 in the middle of the string, the string will just get shorter.
\0 terminates array (string) in C so if you have:
ababaabababa
and you replace second 'a' in pair with \0:
ababa\0baba
effectively for compiler it will be like you just cut this string to:
ababa
Third error here is probably that you are passing two-dimensional array to function here:
char *string[]
This is equivalent to passing char **string and essentialy you are passing array of strings while you wanna only to pass a string (which means a pointer, which means an array: char *string or ofc char string[])
Next thing: you are making internal assumption that passed string will have less than 24 chars (+ \0) but you don't check it anywhere.
I guess easiest way (though maybe not the most clever) to remove duplicated chars is to copy in this for loop passed string to another one, omitting repeated characters.
One example, It does not modify input string and returns a new dynamically allocated string. Pretty self explanatory I think:
char *new_string_without_dups(const char *input_str, size_t len)
{
int i = 1;
int j = 0;
char tmpstr[len+1] = {0};
for (; i < len; i++) {
if (input_str[i] == input_str[i-1]) {
continue;
}
tmpstr[j] = input_str[i];
j++;
}
return strdup(tmpstr);
}
Don't forget to free the returned string after usage.
Note that there are several ways to adapt/improve this. One thing now is that it requires C99 std due to array size not being known at compile time. Other things like you can get rid of the len argument if you guarantee a \0 terminated string as input. I'll leave that as excercises.
Your idea behind the code is right, but you are making two fundamental mistakes:
You return a char [] from a function that has char as return type. char [], char * and char are three different types, even though in this case char [] and char * would behave identically. However you would have to return char * from your function to be able to return a string.
You return automatically allocated memory. In other languages where memory is reference counted this is OK. In C this causes undefined behavior. You cannot use automatic memory from within a function outside this very function. The memory is considered empty after the function exits and will be reused, i.e. your value will be overwritten. You have to either pass a buffer in, to hold the result, or do a dynamic allocation within the function with malloc(). Which one you do is a matter of style. You could also reuse the input buffer, but writing the function like that is undesirable in any case where you need to preserve the input, and it will make it impossible for you to pass const char* into the function i.e. you would not be able to do do something like this:
const char *str = "abbc";
... doubleletter(str,...);
If I had to write the function I would probably call it something like this:
int doubleletter (const char *in, size_t inlen, char *out, size_t outlen){
int i;
int j = 0;
if (!inlen) return 0;
if (!outlen) return -1;
out [j++] = in[0];
for (i = 1; i < inlen; ++i){
if (in[i - 1] != in[i]){
if (j > outlen - 1) return -1;
out[j++] = in[i];
}
}
out[j] = '\0';
return j - 1;
}
int main(void) {
const char *str1 = "aabbaa";
char out[25];
int ret = doubleletter(str1, strlen(str1), out, sizeof(out)/sizeof(out[0]));
printf("Result: %s", out);
return 0;
}
I would recommend using 2 indices to modify the string in-place:
void remove_doubles(char *str)
{
// if string is 1 or 0 length do nothing.
if(strlen(str)<=1)return;
int i=0; //index (new string)
int j=1; //index (original string)
// loop until end of string
while(str[j]!=0)
{
// as soon as we find a different letter,
// copy it to our new string and increase the index.
if(str[i]!=str[j])
{
i++;
str[i]=str[j];
}
// increase index on original/old string
j++;
}
// mark new end of string
str[i+1]='\0';
}

Inserting a string into another string no library functions

I am attempting to complete a homework assignment, part of which is to design a function that inserts a string into another string. All functions, with the exception of strlen(), are off limits to me. Specifically the problem is this: I am having trouble implementing the part of the function that "makes room" in the target string for the inserted string. Inserting the string always results in a trampling of array elements. Can anyone point out what I am doing wrong here? Thanks for helping me learn!
Edit: Integer n is the location in the string that I am supposed to insert the other string.
void insertstring(char *str, char *ins, int n)
{
int i;
int scoot=strlen(ins);
char *p=str+n;
for (i=strlen(str); i > n; --i) { //This is where I'm doing it wrong I think
str[i+scoot]=str[i]; //
}
do {
*p = *ins;
++p;
++ins;
}
while (*ins != '\0');
}
An elegant solution uses reversing to achieve the desired result. Assume your target string, str, is composed of two blocks, AB, where A is the block before the insertion point, and B is the block after insertion point. Furthermore, assume that the string to insert, ins, is denoted by a third block C.
It can be seen that if you concatenate C to AB and then reverse B, reverse C, and reverse both B and C, you get ACB, which is the desired result. More explicitly, this is what you have after appending C to AB:
ABC
And this is what you want:
ACB
ACB can be obtained by:
Reverse B, to get B_r (B reversed);
Reverse C, to get C_r - at this point we have AB_rC_r;
Reverse both B and C, that is, compute A(B_rC_r)_r, which yields ACB.
Here's the code that implements this algorithm:
void reverse(char *, char *, char *);
/* Insert string C between blocks AB in str */
void insertstring(char *str, char *ins, int n) {
/* 1 - Append C to the end of str */
int i = strlen(str);
char *p = str+i, *q = ins;
while ((*p++ = *q++));
p--;
/* 2 - Reverse C and B */
reverse(str, str+i, p-1); /* C */
reverse(str, str+n, str+i-1); /* B */
/* 3 - Reverse B_rC_r */
reverse(str, str+n, p-1);
}
void reverse(char *str, char *begin, char *end) {
char tmp;
while (begin < end) {
tmp = *begin;
*begin = *end;
*end = tmp;
begin++;
end--;
}
}
And some sample code to test it:
#include <stdio.h>
#include <string.h>
int main() {
void insertstring(char *, char *, int);
char test[128] = "A string to test.";
printf("Before: %s\n", test);
insertstring(test, "hello!", 4);
printf("After: %s\n", test);
return 0;
}
This will insert "hello!" beginning in test[4]. Here's the output:
$ ./test
Before: A string to test.
After: A sthello!ring to test.
Consider taking this approach: the code is short and elegant. This technique is described in Programming Pearls, 2nd edition, as a good way to perform vector rotation. According to the author, Brian Kernighan and P.J. Plauger used precisely this method in their Software Tools in Pascal to move lines within a text editor.
First you have change
for (i=strlen(str); i > n; --i)
to
for (i=strlen(str); i >= n; --i)
because you have to move str[n] too.
The other problem is when you insert ins:
do {
*p = *ins;
++p;
++ins;
}
while (*ins != '\0');
Here you copy the terminating '\0' from ins to str so the rest is lost. Change it to
while (*ins != '\0') {
*p = *ins;
++p;
++ins;
}
After mentioning about n, update for loop as
for (i=n+scoot; i >= n; i--)
You want to move strlen(ins) number of character ahead from location n.
Tried it with single loop,
go to index , copy src content into temp_array and simultaneously copying medi into src
once medi is copied completely , start putting the content of temp_array till it become empty
void insert_in_middle (char *src, char *medi, int index)
{
int i=0, j = index, k=0;
char temp_array[50];
while(src[j] != '\0' || temp_array[k] != '\0')
{
temp_array[i] = src[j];
if(medi[i] != '\0')
{
src[j] = medi[i];
}
else if(temp_array[k] != '\0')
{
src[j] = temp_array[k];
k++;
}
i++; j++;
}
printf("src[%s]\n", src);
printf("medi[%s]\n",medi);
printf("temp_array[%s]\n",temp_array);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *str_ins();
int main()
{
char *test = "Hello, world!";
printf("%s\n",test);
str_ins(&test,strstr(test,"world"),"my ");
printf("%s\n",test);
}
char *str_ins(a, b, c) // insert string c into a at point b
char **a, *b, *c;
{
char *stemp;
int pos = strlen(*a) - strlen(b);
stemp = (char *) malloc(strlen(*a)+strlen(c)+1);
strncpy(stemp,*a,pos);
strcpy(stemp+pos,c);
strcat(stemp,b);
free(a);
*a = stemp;
return *a;
}

C replace char in char array

Folks, need to search through a character array and replace any occurrence of '+','/',or'=' with '%2B','%2F', and '%2F' respectively
base64output variable looks like
FtCPpza+Z0FASDFvfgtoCZg5zRI=
code
char *signature = replace_char(base64output, "+", "%2B");
signature = replace_char(signature, "/", "%2F");
signature = replace_char(signature, "=", "%3B");
char replace_char (char *s, char find, char replace) {
while (*s != 0) {
if (*s == find)
*s = replace;
s++;
}
return s;
}
(Errors out with)
s.c:266: warning: initialization makes pointer from integer without a cast
What am i doing wrong? Thanks!
If the issue is that you have garbage in your signature variable:
void replace_char(...) is incompatible with signature = replace_char(...)
Edit:
Oh I didn't see... This is not going to work since you're trying to replace a char by an array of chars with no memory allocation whatsoever.
You need to allocate a new memory chunk (malloc) big enough to hold the new string, then copy the source 's' to the destination, replacing 'c' by 'replace' when needed.
The prototype should be:
char *replace_char(char *s, char c, char *replace);
1.
for char use '' single quotes
for char* use "" double quotes
2.
The function does include the return keyword, therefore it does not return what you'd expect
3.
These webpages have examples on string replacement
http://www.cplusplus.com/reference/cstring/strstr/
What is the function to replace string in C?
You could go for some length discussing various ways to do this.
Replacing a single char is simple - loop through, if match, replace old with new, etc.
The problem here is that the length of the "new" part is longer than the length of the old one.
One way would be to determine the length of the new string (by counting chars), and either (1) try to do it in place, or (2) allocate a new string.
Here's an idea for #1:
int replace(char *buffer, size_t size, char old, const char *newstring)
{
size_t newlen = strlen(newstring);
char *p, *q;
size_t targetlen = 0;
// First get the final length
//
p = buffer;
while (*p)
{
if (*p == old)
targetlen += newlen;
else
targetlen++;
++p;
}
// Account for null terminator
//
targetlen++;
// Make sure there's enough space
//
if (targetlen > size)
return -1;
// Now we copy characters. We'll start at the end and
// work our way backwards.
//
p = buffer + strlen(buffer);
q = buffer + targetlen;
while (targetlen)
{
if (*p == old)
{
q -= newlen;
memcpy(q, newstring, newlen);
targetlen -= newlen;
--p;
}
else
{
*--q = *p--;
--targetlen;
}
}
return 0;
}
Then you could use it this way (here's a quick test I did):
char buf[4096] = "hello world";
if (replace(buf, sizeof(buf), 'o', "oooo"))
{
fprintf(stderr, "Not enough space\n");
}
else
{
puts(buf);
}
your replace_char signature returns void
void replace_char (char *s, char find, char replace)
But, when the linker tries to resolve the following
signature = replace_char(signature, "=", '%3B');
It doesn't find any function that's called replace_char and returns int (int is the default if there's no prototype).
Change the replace_char function prototype to match the statement.
EDIT:
The warning states that your function returns char, but you use it as a char *
also, your function doesn't return anything, do you need to return something ?
It looks like you don't really understand the code that you're working with.
Fixing errors and warnings without understanding exactly what you need to do is worthless..
fix like this
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace_char (char *str, char find, char *replace) {
char *ret=str;
char *wk, *s;
wk = s = strdup(str);
while (*s != 0) {
if (*s == find){
while(*replace)
*str++ = *replace++;
++s;
} else
*str++ = *s++;
}
*str = '\0';
free(wk);
return ret;
}
int main(void){
char base64output[4096] = "FtCPpza+Z0FASDFvfgtoCZg5zRI=";
char *signature = replace_char(base64output, '+', "%2B");
signature = replace_char(signature, '/', "%2F");
signature = replace_char(signature, '=', "%3B");
printf("%s\n", base64output);
return 0;
}
below is a code that ACTUALLY WORKS !!!!
Ammar Hourani
char * replace_char(char * input, char find, char replace)
{
char * output = (char*)malloc(strlen(input));
for (int i = 0; i < strlen(input); i++)
{
if (input[i] == find) output[i] = replace;
else output[i] = input[i];
}
output[strlen(input)] = '\0';
return output;
}

Resources