Need help understanding this C program which simulates strcpy() with a function - c

This is my code. I am trying to simulate strcpy(). This code works, but I have a couple questions.
#include <stdio.h>
#include <stdlib.h>
char *strcpy(char *d, const char *s);
int main()
{
char strOne[] = "Welcome to the world of programming!";
char strTwo[] = "Hello world!";
printf("String One: %s\n", strOne);
printf("String Two before strcpy(): %s\n", strTwo);
strcpy(strTwo, strOne);
printf("String Two after strcpy(): %s\n", strTwo);
return 0;
}
char *strcpy(char *d, const char *s)
{
while (*s)
{
*d = *s;
d++;
s++;
}
*d = 0;
return 0;
}
When *s gets incremented to the position where '\0' is stored in the array, is that when the while condition becomes false because of '\0'? Does while read '\0' or just '0'?
'while' condition will be true if it reads '1'. All previous values of *s should be read as single characters in while condition, but the loop executes anyways. Why does this happen? Do all the single characters from the array *s is pointing equate to the value '1'?
What does *d = 0; exactly do? The way I understand it, the copying process is completed when the while loop is exited. So why does removing *d = 0 lead to an incorrect output being displayed?
Output without *d = 0 :
String Two before strcpy(): Hello world!
String Two after strcpy(): Welcome to the world of programming! programming!
Output with *d = 0 :
String Two before strcpy(): Hello world!
String Two after strcpy(): Welcome to the world of programming!

The characters in the ASCII table assume values that range from 0 to 127, 0 being NULL or '\0', so the condition is always true unless the character is '\0'.
*d = 0 places a '\0' at the end of the string; it's how strings are terminated in C. If you don't terminate the string, anything can be printed past the end of the string, and the program has no way to know where it ends. It's undefined behaviour.

Some more remarks. You return 0 instead of pointer to char. You should get some warnings. Return the copy instead. BTW this function can be simplified a bit as well.
char *strcpy(char *d, const char *s)
{
char *saved = d;
while ((*d++ = *s++));
return saved;
}

Related

C: If a substring exists inside a string, then change the small letters in the string to capital letters

I'm writing a program to capitalize substrings in a string in C.
Here are examples to illustrate my expected output:
String: "hello world"
Substring: "wo"
Output: "hello WOrld"
String: "I don't know how to do this"
Substring: "do"
Output: "I DOn't know how to DO this"
String: "mouse is useful thing"
Substring: "use"
Output: "moUSE is USEful thing"
String: "replace occurrences of 'r'"
Substring: "r"
Output: "Replace occuRRences of 'R'"
Basically, anywhere the substring exists in the string, uppercase it in the original string.
Here's my code:
void replaceSubstring(char *str, char *substr) {
char *p = str;
char *k = substr;
int substringLength = strlen(k);
while (*p)
{
if (strncmp(p, k, substringLength) == 0)
{
for (p; p < p + substringLength; p++)
{
*p = *p - 32;
}
}
p++;
}
puts(p);
printf("\n");
}
However, my code is crashing. My approach is to loop while the character is not '\0' and check if the substring is located somewhere within the string (using the strncmp function), and if it is, I'd like to change the value *p to a capital letter by decreasing its ASCII value by 32.
Why doesn't it work? Where is the mistake?
The primary issue with your inner loop is that p can't be used both as the termination target (p + substringLength) and
as the counter. It's like saying for (int i = 0; i < i + 10; i++). Will i ever reach i + 10?
You might try setting the p + substringLength to a variable len, then using that fixed goalpost as the loop termination condition.
Secondly, use toupper() to make the character conversion. Otherwise, spaces and non-alphabetical characters will also be modified, causing unexpected behavior. For example, spaces would be turned into null terminating characters, orphaning the tail of the string.
Putting it together yields:
for (char *len = p + substringLength; p < len; p++)
{
*p = toupper(*p);
}
Finally, puts(p); doesn't work as you expect. By the end of the function, p was used to iterate through the string and now points to the end of the string, not the beginning. Use puts(str); or simply print from the calling scope to avoid side effects.
Here's a complete example:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
void replaceSubstring(char *str, char *substr) {
char *p = str;
int substringLength = strlen(substr);
while (*p)
{
if (strncmp(p, substr, substringLength) == 0)
{
for (char *len = p + substringLength; p < len; p++)
{
*p = toupper(*p);
}
}
p++;
}
}
int main(void) {
char s[12] = "hello world";
replaceSubstring(s, "llo wor");
printf("%s\n", s);
replaceSubstring(s, "ll");
printf("%s\n", s);
replaceSubstring(s, "h");
printf("%s\n", s);
replaceSubstring(s, "hello worldz");
printf("%s\n", s);
char t[28] = "i don't know how to do this";
replaceSubstring(t, "do");
printf("%s\n", t);
replaceSubstring(t, "'t know");
printf("%s\n", t);
return 0;
}
Output:
heLLO WORld
heLLO WORld
HeLLO WORld
HeLLO WORld
i DOn't know how to DO this
i DOn'T KNOW how to DO this
Try it!
For single string & single pattern, you may use kmp.
https://www.geeksforgeeks.org/kmp-algorithm-for-pattern-searching/
For a set of strings & a single pattern, a fsm based algorithm may required.
https://www.geeksforgeeks.org/finite-automata-algorithm-for-pattern-searching/
They are pretty classic algorithms, and already talked pretty a lot.

cutting a string when a character is found

I wrote a function that cuts the string "hello world" to "hell" if a 'o' is found.
I keep getting a segmentation fault. I don't know where the mistake could be.
Could anyone help?
Thank you in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cutString(char* str, char del){
char *newstring =(char*) str;
malloc(sizeof(char)*strlen(str));
int i= 0;
for(; newstring[i]!='\0'&&newstring[i]!=del;i++);
if(i==strlen(newstring))
printf("not found");
else
newstring[i]='\0';
return newstring;
}
int main(){
cutString("Hello World",'o');
return 0;
}
There are two major problems with your code:
char *newstring =(char*) str makes newstring point to the old str. And since you pass a literal string (which is read only) you will have undefined behavior attempting to modify it.
malloc(sizeof(char)*strlen(str)); is a memory leak. And doesn't allocate space for the terminator.
The crash is probably because point one, when you attempt to modify the read-only string literal.
There are a number of problems in your code. The main problem is that you don't assign the return value from malloc to newstring. Besides that you need to malloc an extra byte for the string termination.
Further, your loop must copy characters from str into newstring.
In main you must assign the return value from the function to a char pointer variable to get hold of the new string.
Something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cutString(char* str, char del){
char *newstring = malloc(strlen(str) + 1); // malloc into newstring
int i= 0;
while (newstring[i]!='\0' && str[i] != del) // Stop when a) no more chars in str or b) "del" is found
{
newstring[i] = str[i]; // Copy character from str to newstring
++i;
}
newstring[i]='\0'; // Terminate the string
return newstring;
}
int main(){
char* newstring = cutString("Hello World",'o'); // Save the returned value
printf("%s\", newstring);
free(newstring);
return 0;
}
newstring[i]='\0';
This line is invalid. Modifying string literals is undefined behavior. I would suggest check this out :segmentation fault when using pointer
A better solution would be to use arrays instead of pointers

Pointers in C resulting in unknown random char

I have some C code to print a string char array twice.
Code:
char* twice(char *s) {
int size=strlen(s),i=0;
int length=size*2;
char check = s[size-1];
char* s2 = malloc(length * sizeof(char));
char* reset = malloc(size * sizeof(char));
memcpy(reset, s, size * sizeof(char));
while (i<length) {
printf("%s\n", s);
s2[i] = *s;
if(s2[i] == check && i == size-1){
s = reset;
}else s++;
i++;
}
return s2;
}
int main(){
char s[] = "hello1234";
printf("%s\n", twice(s));
return 0;
}
Output:
hello1234
ello1234
llo1234
lo1234
o1234
1234
234
34
4
hello1234
ello1234
llo1234
lo1234
o1234
1234
234
34
4
hello1234hello1234Ms?
The inputted string is hello1234 and i am printing out each pointer to show that it correctly runs through the string twice. But for some reason the answer includes Ms? resulting in hello1234hello1234Ms? why is that?
In C, strings are terminated with a special character with the value '\0'.
memcpy() works with memory, it is not specific to strings. And so it does not copy the terminator since you didn't give it a length that includes the terminator. (strlen() does not include the terminator.)
When printf() doesn't find the terminator, it just keeps printing whatever is in memory. The additional characters are just random and will be different on different set ups.

Resultant string utilising puts and strcat showing extra characters

#include<stdio.h>
#include<string.h>
int main()
{
char c='g';
char d[]="John ";
strcat(d,&c);
puts(d);
return 0;
}
The output is:
John gC
The 'C' wasn't required.
Also, what does const char* mean here?
char *strcat(char *dest, const char *src)
Also, is a statement like this (inside a loop) wrong somewhere if I wish to add a character at the end of string?
char arr[]=' ';
symb[]={'a','b','c'}
strcat(arr, &symb[k]);
k++;
You are writing out of the bounds of d, you need room for one more char, change to
char d[7] = "John ";
or (if you don't want to specify the size of the array):
char d[] = "John \0";
or
char d[] = {'J', 'o', 'h', 'n', ' ', '\0', '\0'};
Also strcat wants a valid NUL terminated string and you are passing a pointer to a single char, change to
char *c= "g";
Two ways(there are even more):-
1>
char *c="g";
char d[10]="John ";
strcat(d,c);
2>
char c[]="g";
char d[10]="John ";
strcat(d,c);
Though I advise d[10] = {0} ; and then copy the string. (as David mentioned in comments.)
You need to learn the basics of C and C-style strings. Specifically, that a special zero-value character identifies the end of the string.
You have copied over the string but you did not copy the terminator. Therefore, functions like puts() don't know when to stop and print other characters that happen to be in memory.
There is undefined behaviour in your program . strcat requires null terminated string as its arguments where c is not . You can do this-
char c[]="g";
char d[7]="John "; // leave space for 'g' as well as for '\0'
strcat(d,c); // then pass both to strcat
Another way is to use sprintf -
char c[]="g";
char d[10]="John";
size_t n =strlen(d);
sprintf(&d[n]," %s",c);
This works: ( if you wanted John g )
#include<stdio.h>
#include<string.h>
int main()
{
char c='g';
char d[10];
char temp[2];
strcpy(d ,"John ");
temp[0]=c;
temp[1]='\0';
strcat( d , temp );
puts(d);
return 0;
}
This works: ( if you wanted Johng )
#include<stdio.h>
#include<string.h>
int main()
{
char c='g';
char d[]="John ";
//strcat(d,&c);
d[strlen(d)-1]=c;
puts(d);
return 0;
}

How would I replace the character in this example using strchr?

/* strchr example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char * pch;
printf ("Looking for the 's' character in \"%s\"...\n",str);
pch=strchr(str,'s');
while (pch!=NULL)
{
printf ("found at %d\n",pch-str+1);
pch=strchr(pch+1,'s');
}
return 0;
}
How would I index the str so that I would replace every 's' with 'r'.
Thanks.
You don't need to index the string. You have a pointer to the character you want to change, so assign via the pointer:
*pch = 'r';
In general, though, you index using []:
ptrdiff_t idx = pch - str;
assert(str[idx] == 's');
You can use the following function:
char *chngChar (char *str, char oldChar, char newChar) {
char *strPtr = str;
while ((strPtr = strchr (strPtr, oldChar)) != NULL)
*strPtr++ = newChar;
return str;
}
It simply runs through the string looking for the specific character and replaces it with the new character. Each time through (as with yours), it starts with the address one beyond the previous character so as to not recheck characters that have already been checked.
It also returns the address of the string, a trick often used so that you can use the return value as well, such as with:
printf ("%s\n", chngChar (myName, 'p', 'P'));
void reeplachar(char *buff, char old, char neo){
char *ptr;
for(;;){
ptr = strchr(buff, old);
if(ptr==NULL) break;
buff[(int)(ptr-buff)]=neo;
}
return;
}
Usage:
reeplachar(str,'s','r');
Provided that your program does really search the positions without fault (I didn't check), your question would be how do I change the contents of an object to which my pointer pch is already pointing?

Resources