Changing character in a string to two characters - c

Hello I have a problem with strchr() because yea it will return the pointer to the first occurance of the character but how do I get the index from that to be able to change it? and how can I change one character to two characters?
So I need to change every 'x' in the src to 'ks' in the dest.
My code:
#include <stdio.h>
#include <string.h>
void antikorso(char *dest, const char *src) {
strcpy(dest, src);
if (strchr(dest, 'x')) {
}
printf("\n%s", dest);
}
int main(void) {
const char *lol = "yxi yxi";
char asd[1000];
antikorso(asd, lol);
}

You can do:
void antikorso(char *dest, const char *src) {
const char *p = src;
int i;
for (i = 0; *p != '\0'; i++, p++) {
if (*p != 'x') {
dest[i] = *p;
} else {
dest[i++] = 'k';
dest[i] = 's';
}
}
dest[i] = '\0';
printf("\n%s", dest);
}

following lines of code might be helpful :
#include <stdio.h>
#include <string.h>
void antikorso(char *dest, const char *src) {
int j=0;
for(int i=0;i<strlen(src);i++)
{
if (src[i] == 'x')) {
dst[j]='k';
j++;
dst[j] = 's';
j++;
}
else
{
dst[j] = stc[i];
j++;
}
i++;
}
dst[j] = '\0';
printf("\n%s", dest);
return dest;
}
int main(void) {
const char *lol = "yxi yxi";
char asd[1000];
antikorso(asd, lol);
}

You may not need the index, just a pointer. The "index" would be the offset from the beginning, so dest[i], which is the same as dest + i, which is the address of dest, plus i characters further. So you can use:
char *cp;
if (cp=strchr(dest, 'x')) {
*cp= 'y';
But if you do want the index, it is just
if (cp=strchr(dest, 'x')) {
int i = cp - dest;

Other answers not being incorrect, just want to address an important issue: You are not safe from undefined behaviour by writing past the end of your target buffer (same problem as with so many stdlib functions like strcpy or strcat nowadays considered insecure)! So I strongly recommend modifying your function signature (if you have the freedom to do so):
size_t antikorso(char* dest, size_t length, const char* src)
// ^^ ^^
{
char* d = dest;
char* end = d + length;
for(; *src; ++src, ++d)
{
// not much different than the other answers, just the range checks...
if(d == end)
break;
*d = *src;
if(*d == 'x')
{
*d = 'k'
if(++d == end)
break;
*d = 's';
}
}
// now null-terminate your string;
// first need to get correct position, though,
// in case the end of buffer has been reached:
d -= d == end;
// this might possibly truncate a trailing "ks";
// if not desired, you need extra checks...
*d = 0;
return d - dest;
}
The return value does not add anything to safety, but prevents you from having to call strlen on the output, once written...

If strchr returns a valid address, you can use pointer arithmetic to get the index, by subtracting the "base address" - that is, the pointer to the first element of the array.
#include <string.h>
#include <stddef.h> // NULL, ptrdiff_t
const char* result = strchr(dest, 'x');
if ( result != NULL)
{
ptrdiff_t index = result - dest;
... // do stuff with index
}
ptrdiff_t is a standard C integer type suitable for expressing the result of pointer arithmetic.

Related

Why my returned value of strchr is ignored?

I have to make a function, that will code my sentence like this: I want to code all words with an o, so for example I love ice cream becomes I **** ice cream.
But my function ignores the result of strchr. And I don't know why.
This is my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define LEN 1000
char *Shift(char *str, char *let) {
const char *limits = " ,-;+.";
char copy[LEN];
strcpy(copy, str);
char *p;
char *ptr;
ptr = strtok(copy, limits);
for (int j = 0; ptr != NULL; ptr = strtok(NULL, limits), ++j) {
int len = 0;
if (strchr(ptr, let) != NULL) {
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
}
}
return str;
}
int main() {
char *s = Shift("I love my cocktail", "o");
puts(s);
}
Expected output is: I **** my ********
but I've got just printed the original string
For starters the function strchr is declared like
char *strchr(const char *s, int c);
that is its second parameter has the type int and the expected argument must represent a character. While you are calling the function passing an object of the type char * that results in undefined behavior
if (strchr(ptr, let) != NULL) {
It seems you mean
if (strchr(ptr, *let) != NULL) {
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior and this code snippet
p = strstr(str, ptr);
for (int i = 0; i < strlen(ptr); i++) {
p[i] = "*";
}
tries to change the string literal passed to the function
char *s = Shift("I love my cocktail", "o");
And moreover in this statement
p[i] = "*";
you are trying to assign a pointer of the type char * to a character. At least you should write
p[i] = '*';
If you want to change an original string you need to store it in an array and pass to the function the array instead of a string literal. For example
char s[] = "I love my cocktail";
puts( Shift( s, "o" ) );
Pay attention to that there is no great sense to declare the second parameter as having the type char *. Declare its type as char.
Also the function name Shift is confusing. You could name it for example like Hide or something else.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
char * Hide( char *s, char c )
{
const char *delim = " ,-;+.";
for ( char *p = s += strspn( s, delim ); *p; p += strspn( p, delim ) )
{
char *q = p;
p += strcspn( p, delim );
char *tmp = q;
while ( tmp != p && *tmp != c ) ++tmp;
if ( tmp != p )
{
for ( ; q != p; ++q ) *q = '*';
}
}
return s;
}
int main( void )
{
char s[] = "I love my cocktail";
puts(s);
puts( Hide( s, 'o' ) );
}
The program output is
I love my cocktail
I **** my ********
The for loop
for ( ; q != p; ++q ) *q = '*';
within the function can be rewritten as a call of memset
memset( q, '*', p - q );
There are multiple problems:
copying the string to a fixed length local array char copy[LEN] will cause undefined behavior if the string is longer than LEN-1. You should allocate memory from the heap instead.
you work on a copy of the string to use strtok to split the words, but you do not use the correct method to identify the parts of the original string to patch.
you should pass a character to strchr(), not a string.
patching the string with p[i] = "*" does not work: the address of the string literal "*" is converted to a char and stored into p[i]... this conversion is meaningless: you should use p[i] = '*' instead.
attempting to modify a string literal has undefined behavior anyway. You should define a modifiable array in main and pass the to Shift.
Here is a corrected version:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *Shift(char *str, char letter) {
const char *limits = " ,-;+.";
char *copy = strdup(str);
char *ptr = strtok(copy, limits);
while (ptr != NULL) {
if (strchr(ptr, letter)) {
while (*ptr != '\0') {
str[ptr - copy] = '*';
ptr++;
}
}
ptr = strtok(NULL, limits);
}
free(copy);
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
The above code still has undefined behavior if the memory cannot be allocated. Here is a modified version that operates in place to avoid this problem:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, char letter) {
char *ptr = str;
while ((ptr = strchr(ptr, letter)) != NULL) {
char *p = ptr;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my cocktail";
puts(Shift(s, 'o'));
return 0;
}
Note that you can also search for multiple characters at a time use strcspn():
#include <ctype.h>
#include <stdio.h>
#include <string.h>
char *Shift(char *str, const char *letters) {
char *ptr = str;
while (*(ptr += strcspn(ptr, letters)) != '\0') {
char *p = str;
while (p > str && isalpha((unsigned char)p[-1]))
*--p = '*';
while (isalpha((unsigned char)*ptr)
*ptr++ = '*';
}
return str;
}
int main() {
char s[] = "I love my Xtabentun cocktail";
puts(Shift(s, "oOxX"));
return 0;
}

Argv doesnt work with char pointer on terminal

I want to write a program that when I am on terminal and write prog.exe -u word will transform word to uppercase otherwise skip the process. but when I compile the code below, I get nothing on screen and I couldn't figure out why the error occurs.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char u[] = "-u";
void upper(const char *src, char *dest);
int main(int argc, char const *argv[]) {
if (argc < 3) {
printf("Input at least 3 argument!\n");
} else
if (!(strcmp(argv[1], u))) {
char *output;
upper(argv[2], output);
printf("%s\n", output);
} else {
printf("No option\n");
}
return 0;
}
void upper(const char *src, char *dest) {
while (*src) {
if (*src >= 97 && *src <= 122) {
*dest = *src - 32;
} else {
*dest = *src;
}
src++;
dest++;
}
*dest = *src;
}
The pointer output declared like
char * output;
is uninitialized and has an indeterminate value.
So using it in the function upper invokes undefined behavior.
Instead of the pointer you should use a character array large enough to store the passed string to the function.
If the compiler supports variable length arrays then you can write
char output[ strlen( argv[2] ) + 1 ];
And this if statement
else if( strcmp(argv[1],u) == 0 ){
will be more readable than this if statement
else if(!(strcmp(argv[1],u))){
Within the function it will be at least better to use character symbols 'a' and 'z' instead of the magic numbers 97 and 122 in the if statement
if(*src >= 97 && *src <= 122){
*dest = *src - 32;
}
Though it is even better to use standard function islower and toupper declared in the header <ctype.h>.
The function can be declared and defined the following way
#include <ctype.h>
//...
char * upper( char *dest, const char *src )
{
char *result = dest;
do
{
if ( islower( ( unsigned char )*src ) )
{
*dest++ = toupper( ( unsigned char )*src );
}
else
{
*dest++ = *src;
}
} while ( *src++ );
return result;
}
void upper(const char *src, char *dest) {
char *tmp = dest; // hold pointer
while(*src) {
*dest = (*src >= 97 && *src <= 122) ? *src - 32 : src;
++src; ++dest;
}
*dest = '\0'; // end of string
dest = tmp;
}
The program has undefined behavior because you attempt to store the converted string to an uninitialized pointer output.
Note that using hard coded constants such as 97, 122 and 32 is both confusing and non portable to non-ASCII environments. You should use the macros and functions from <ctype.h> for readability and portability.
You could simply modify the argument string in place this way:
#include <ctype.h>
#include <stdio.h>
void upper(char *str);
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Input at least 3 arguments!\n");
} else
if (!(strcmp(argv[1], "-u"))) {
printf("%s\n", upper(argv[2]));
} else {
printf("No option\n");
}
return 0;
}
char *upper(char *str) {
for (char *p = str; *p; p++) {
*p = toupper((unsigned char)*p);
}
return str;
}

My own strcat function with pointers does not work right

I am new to pointers and want to learn them well. So this is my own attempt to write my strcat function. If I return just a it prints some binary things (I think it should print the solution), If I return *a it says seg fault core dumped I couldn't find the error. Any help is accepted thanks.
#include <stdio.h>
#include <string.h>
int main() {
char *strcaT();
char *a = "first";
char *b = "second";
printf("%s", strcaT(a, b));
return 0;
}
char *strcaT(char *t, char *s) {
char buffer[strlen(t) + strlen(s) - 1];
char *a = &buffer[0];
for (int i = 0; i < strlen(s) + strlen(t); i++, t++) {
if (*t == '\n') {
for (int i = 0; i < strlen(s);i++) {
buffer[strlen(t) + i] = *(s + i);
}
}
buffer[i] = *(t + i);
}
return a;
}
The code has multiple cases of undefined behavior:
you return the address of a local array in strcaT with automatic storage, which means this array can no longer be used once it goes out of scope, ie: when you return from the function.
the buffer size is too small, it should be the sum of the lengths plus 1 for the null terminator. You write beyond the end of this local array, potentially overwriting some important information such as the caller's framce pointer or the return address. This undefined behavior has a high chance of causing a segmentation fault.
you copy strlen(t)+strlen(s) bytes from the first string, accessing beyond the end of t.
It is unclear why you test for '\n' and copy the second string at the position of the newline in the first string. Strings do not end with a newline, they may contain a newline but and at a null terminator (byte value '\0' or simply 0). Strings read by fgets() may have a trailing newline just before the null terminator, but not all strings do. In your loop, the effect of copying the second string is immediately cancelled as you continue copying the bytes from the first string, even beyond its null terminator. You should perform these loops separately, first copying from t, then from s, regardless of whether either string contains newlines.
Also note that it is very bad style to declare strcaT() locally in main(), without even a proper prototype. Declare this function before the main function with its argument list.
Here is a modified version that allocates the concatenated string:
#include <stdio.h>
#include <stdlib.h>
char *strcaT(const char *s1, const char *s2);
int main() {
const char *a = "first";
const char *b = "second";
char *s = strcaT(a, b);
if (s) {
printf("%s\n", s);
free(s);
}
return 0;
}
char *strcaT(const char *t, const char *s) {
char *dest = malloc(strlen(t) + strlen(s) + 1);
if (dest) {
char *p = dest;
/* copy the first string */
while (*t) {
*p++ = *t++;
}
/* copy the second string at the end */
while (*s) {
*p++ = *s++;
}
*p = '\0'; /* set the null terminator */
}
return dest;
}
Note however that this is not what the strcat function does: it copies the second string at the end of the first string, so there must be enough space after the end of the first string in its array for the second string to fit including the null terminator. The definitions for a and b in main() would be inappropriate for these semantics, you must make a an array, large enough to accommodate both strings.
Here is a modified version with this approach:
#include <stdio.h>
char *strcaT(char *s1, const char *s2);
int main() {
char a[12] = "first";
const char *b = "second";
printf("%s\n", strcaT(a, b));
return 0;
}
char *strcaT(char *t, const char *s) {
char *p = t;
/* find the end of the first string */
while (*p) {
*p++;
}
/* copy the second string at the end */
while (*s) {
*p++ = *s++;
}
*p = '\0'; /* set the null terminator */
return t;
}
It is a very bad idea to return some local variable, it will be cleared after the function finishes its operation. The following function should work.
char* strcaT(char *t, char *s)
{
char *res = (char*) malloc(sizeof(char) * (strlen(t) + strlen(s) + 1));
int count = 0;
for (int i = 0; t[i] != '\0'; i++, count++)
res[count] = t[i];
for (int i = 0; s[i] != '\0'; i++, count++)
res[count] = s[i];
res[count] = '\0';
return res;
}
In the main function
char *strcaT();
It should be declared before main function:
char *strcaT(char *t, char *s);
int main() {...}
You returns the local array buffer[], it's is undefined behavior, because out of strcaT function, it maybe does not exist. You should use the pointer then allocate for it.
The size of your buffer should be +1 not -1 as you did in your code.
char *strcaT(char *t, char *s) {
char *a = malloc(strlen(t) + strlen(s) + 1);
if (!a) {
return NULL;
}
int i;
for(i = 0; t[i] != '\0'; i++) {
a[i] = t[i];
}
for(int j = 0; s[j] != '\0'; j++,i++) {
a[i] = s[j];
}
a[i] = '\0';
return a;
}
The complete code for test:
#include <stdio.h>
#include <stdlib.h>
char *strcaT(char *t, char *s);
int main() {
char *a = "first";
char *b = "second";
char *str = strcaT(a, b);
if (str != NULL) {
printf("%s\n", str);
free(str); // Never forget freeing the pointer to avoid the memory leak
}
return 0;
}
char *strcaT(char *t, char *s) {
char *a = malloc(strlen(t) + strlen(s) + 1);
if (!a) {
return NULL;
}
int i;
for(i = 0; t[i] != '\0'; i++) {
a[i] = t[i];
}
for(int j = 0; s[j] != '\0'; j++,i++) {
a[i] = s[j];
}
a[i] = '\0';
return a;
}
For starters the function strcaT should append the string specified by the second parameter to the end of the string specified by the first parameter. So the first parameter should point to a character array large enough to store the appended string.
Your function is incorrect because at least it returns a (invalid) pointer to a local variable length character array that will not be alive after exiting the function and moreover the array has a less size than it is required to store two strings that is instead of
char buffer[strlen(t) + strlen(s) - 1];
^^^
it should be declared at least like
char buffer[strlen(t) + strlen(s) + 1];
^^^
and could be declared as static
static char buffer[strlen(t) + strlen(s) + 1];
Also the nested loops do not make sense.
Pay attention that you should provide the function prototype before calling the function. In this case the compiler will be able to check passed arguments to the function. And the name of the function strcaT is confusing. At least the function can be named like strCat.
The function can be defined the following way
#include <stdio.h>
#include <string.h>
char * strCat( char *s1, const char *s2 )
{
char *p = s1 + strlen( s1 );
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
enum { N = 14 };
char s1[N] = "first";
char *s2 = "second";
puts( strCat( s1, s2 ) );
return 0;
}
The program output is
firstsecond
On the other hand if you are already using the standard C function strlen then why not to use another standard C function strcpy?
With this function your function could be defined more simpler like
char * strCat( char *s1, const char *s2 )
{
strcpy( s1 + strlen( s1 ), s2 );
return s1;
}
If you want to build a new character array that contains two strings one appended to another then the function can look for example the following way.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * strCat( const char *s1, const char *s2 )
{
size_t n1 = strlen( s1 );
char *result = malloc( n1 + strlen( s2 ) + 1 );
if ( result != NULL )
{
strcpy( result, s1 );
strcpy( result + n1, s2 );
}
return result;
}
int main(void)
{
char *s1 = "first";
char *s2 = "second";
char *result = strCat( s1, s2 );
if ( result ) puts( result );
free( result );
return 0;
}
Again the program output is
firstsecond
Of course calls of the standard C function strcpy you can substitute for your own loops but this does not make great sense.
If you are not allowed to use standard C string functions then the function above can be implemented the following way.
#include <stdio.h>
#include <stdlib.h>
char * strCat( const char *s1, const char *s2 )
{
size_t n = 0;
while ( s1[n] != '\0' ) ++n;
for ( size_t i = 0; s2[i] != '\0'; )
{
n += ++i;
}
char *result = malloc( n + 1 );
if ( result != NULL )
{
char *p = result;
while ( ( *p = *s1++ ) != '\0' ) ++p;
while ( ( *p = *s2++ ) != '\0' ) ++p;
}
return result;
}
int main(void)
{
char *s1 = "first";
char *s2 = "second";
char *result = strCat( s1, s2 );
if ( result ) puts( result );
free( result );
return 0;
}
I have changed your program to look like below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* strcaT();
char* a = "first";
char* b = "second";
printf("%s",strcaT(a,b));
return 0;
}
char* strcaT(char *t, char *s)
{
char* a = (char*)malloc(sizeof(char)*(strlen(t) + strlen(s) + 1));
for(int i=0; i<strlen(t); i++) {
a[i] = t[i];
}
for(int i=0; i<strlen(s); i++) {
a[strlen(t) + i] = s[i];
}
a[strlen(t)+strlen(s)] = '\0';
return a;
}
You are getting segfault because you are returning address of a local array which is on stack and will be inaccessible after you return. Second is that your logic is complicated to concatenate the strings.

returning string of chars in C

i compiled my piece of code and it worked fine using printf , but i want it to be returned without being printed ..
char *ft_strrev(char *str)
{
int i = 0;
while (str[i] != '\0')
{
i++;
}
while (i != 0)
{
i--;
}
return str;
}
int main ()
{
char *string;
string = "amrani";
ft_strrev(string);
}
The main thing here is to reverse the input entred ..
how can i exactly use return , to return the full char given to my var string , any tips ?
There are two approaches to doing this: make a new string and return it or mutate the parameter in place. Here's a new string version per your clarification comment. Note that memory is allocated for the new string and the caller is expected to free the result:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *ft_strrev(char *str)
{
int len = strlen(str);
char *reversed = malloc(sizeof(*reversed) * (len + 1));
reversed[len] = '\0';
while (*str != '\0')
{
reversed[--len] = *str++;
}
return reversed;
}
int main()
{
char *string = "amrani";
char *reversed = ft_strrev(string);
printf("%s\n", reversed);
free(reversed);
}
Note that many functions of this kind will include the length of the string as a second parameter so the function needn't call strlen.
This solution inverts the string in place.
#include <stdio.h>
#include <string.h>
char *ft_strrev(char *str)
{
int len = strlen(str);
for (int i = 0; i < len / 2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
return str;
}
int main()
{
char string[] = "amrani";
ft_strrev(string); // return value of ft_strrev not used here
printf("%s", string);
}
Be aware of the difference betwween this:
char string[] = "amrani"; // string is an array of chars initialized with "amrani"
and this:
char *string = "amrani"; // string is a pointer to the string literal "amrani"
Modifying a string literal results in undefined behaviour, most likely some crash on modern platforms.

replacing spaces with %20 in c program

I have written the following program to replace spaces with %20.It works fine.
But it prints some garbage values for the pointer variable ptr though it might have been limited to 8 characters as the malloc assigns it 8 bytes of memory.
Can anyone tell me where did I go wrong here ?
Or is there any in place algorithm ?
void replaceSpaces(char *inputStr )
{
char *ptr;
int i,length, spaceCount=0;
int newLength,j;
for (length=0; *(inputStr+length)!='\0';length++ )
{
if (*(inputStr+length)==' ')
{
spaceCount++;
}
}
newLength = length + 2*spaceCount;
ptr = (char *)malloc(newLength*sizeof(char));
for ( i = length-1; i >=0; i--)
{
if (*(inputStr+i)==' ')
{
*(ptr+newLength-1)='0';
*(ptr+ newLength-2)='2';
*(ptr+newLength-3)='%';
newLength = newLength -3;
}
else
{
*(ptr+newLength-1) = *(inputStr+i);
newLength = newLength -1;
}
}
for ( i = 0; *(ptr+i)!='\0'; i++)
{
printf("%c",*(ptr+i));
}
}
Either use calloc() to allocate memory for ptr or terminate it with '\0' after allocation.
With your code, ptr never gets terminated with '\0'.
So either change
ptr = (char *)malloc(newLength*sizeof(char));
to
ptr = calloc(newLength*sizeof(char), sizeof(char));
Or add below line after allocating the ptr.
ptr[newLength] = '\0';
If you don't need the converted string, then you don't need to worry about conversion: you can just output characters directly.
void replace_spaces(const char *in) {
for (const char *p=in; *p; p++) {
if (*p == ' ') {
puts("%20");
} else {
putch(*p);
}
}
}
If you do need the converted string, then a useful pattern for this sort of code is to do the string conversion twice; once in "dry-run" mode where you do the conversion but don't write to the result, and once in "live" mode where you're actually writing. In the first pass, you calculate the needed length. This avoids duplication of logic, and makes it more obvious if you've counted the resulting length correctly. Here's some code in that style, with some test-cases.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *replace_spaces(const char *in) {
char *result = 0;
for (int write = 0; write <= 1; write++) {
int n = 0;
for (const char *from = in; ;from++) {
if (*from == ' ') {
if (write) memcpy(result + n, "%20", 3);
n += 3;
} else {
if (write) result[n] = *from;
n++;
}
if (!*from) break;
}
if (!write) result = malloc(n);
}
return result;
}
int main(int argc, char**argv) {
const char*cases[] = {"Hello world", "abc", " sp sp sp "};
for (int i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
char *rep = replace_spaces(cases[i]);
printf("'%s' -> '%s'\n", cases[i], rep);
free(rep);
}
return 0;
}
Assuming that this is going to work on fairly short strings, it is a bit silly to go through the strings twice. If, like in most cases, CPU is more valuable than memory, do:
char *dst = malloc(3*strlen(src) + 1);
char *result = dst;
while (*src) {
if (*src == ' ') {
strcpy(dst, "%20"); dst+=3;
}
else *dst++ = *src;
src++;
}
*dst = 0;
// result is result

Resources