What is the difference between two ways to manipulate strings in C? - c

I want to copy a string "str" to p . First I used the code I commented out, but the output was empty. So I tried the code that is below the commented area, and it worked. What is the difference between the two methods to manipulate strings in C? Thanks in advance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
char *str = "laekfja";
char *p = (char*)malloc(51 * sizeof(char));
//First try.
/* while(*str)
{
*p++ = *str++;
}
*p = '\0';
printf("%s\n", p);
*/
//Second try.
int i = 0;
while(i < strlen(str))
{
p[i] = str[i];
i++;
}
p[i] = '\0';
printf("%s\n", p);
return 0;
}

Both methods work to copy the string. The error in the first method is in printing the copied string out when the loop is complete:
printf("%s\n", p);
At this point, p is pointing to the last character inserted into the copy, the null character, not the beginning of the string. So the printf() correctly prints nothing.

Related

How to remove newline and instead add comma?

In this code, I want to remove the newline. It means whenever I print this variable, it should give me a string without a newline but instead, the comma should replace it. I can directly add a comma when declaring but I want a separate result.
Expecting output
This,is,a,simple,sentence
Code
#include <stdio.h>
#include <string.h>
int main(){
char str[] = "This\nis\na\nsimple\nsentence";
printf("%s\n", str);
}
A simple for loop will do it:
for (int i = 0; i < sizeof(str); i++)
if (str[i] == '\n')
str[i] = ',';
This modifies the original string, rather than creating a new one.
You can create a one-line while loop using the strchr() function from the standard library to replace each newline character with a comma:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "This\nis\na\nsimple\nsentence";
char* np;
while ((np = strchr(str, '\n')) != NULL) *np = ',';
printf("%s\n", str);
return 0;
}
A more efficient way of searching through the string is to use the last-found position (while there is one) as the starting-point for the search in the next loop:
int main()
{
char str[] = "This\nis\na\nsimple\nsentence";
char* np = str;
while ((np = strchr(np, '\n')) != NULL) *np = ',';
printf("%s\n", str);
return 0;
}

Can't modify an array within a loop (C)

I am currently developing a small program requires a function to return a string (character array), and two parameters which are (phrase, c). The 'phrase' is a string input and 'c' is the character which will be removed from the phrase. The left-over spaces will also be removed.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//This method has two parameters: (str, c)
//It will remove all occurences of var 'c'
//inside of 'str'
char * rmchr(char * str, char *c) {
//Declare result array
char *strVal = (char *) malloc(sizeof(char) * strlen(str));
//Iterate through each character
for (int i = 0; i < strlen(str); i++) {
*(strVal+i) = str[i];
//Check if char matches 'c'
if (strVal[i] != *c){
//Assign filtered value to new array
*(strVal+i) = str[i];
printf("%c", strVal[i]);
}
}
return strVal;
}
int main()
{
char * result = rmchr("This is a great message to test with! It includes a lot of examples!","i");
return 1;
}
Inside of the 'rmchr' function (if-statement), the array prints out exactly how I'd like to return it:
Ths s a great message to test wth! It ncludes a lot of examples!
The problem is that my return variable, 'strVal' isn't being modified outside of the if-statement. How can I modify the array permanently so my ideal output will be returned inside of 'result' (inside of main).
I see a few points to address. Primarily, this code directly copies the input string verbatim as it stands. The same *(strVal+i) = str[i]; assignment takes place in two locations in the code which disregards the comparison against *c. Without some secondary index variable j, it becomes difficult to keep track of the end of the receiving string.
Additional notes:
There is no free for your malloc; this creates a memory leak.
You return exit code 1 which indicates abnormal program termination. return 0 to indicate a normal exit.
Don't cast the pointer malloc returns; this can hide errors.
Validate malloc success and exit if it failed.
strlen() is a linear time operation that iterates through the entire parameter string on each call. Call it once and store the result in a variable to save cycles.
This code does not handle removal of extra spaces as required.
See the below sample for a possible implementation that addresses some of the above points:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *rmchr(char *str, char *c) {
int i = 0;
int j = 0;
int len = strlen(str);
char *result = malloc(sizeof(*result) * (len + 1));
if (result == NULL) {
fprintf(stderr, "out of memory\n");
exit(1);
}
while (i < len) {
if (str[i] != *c) {
result[j++] = str[i++];
}
else {
for (i++; i < len && str[i] == ' '; i++);
}
}
result[j] = '\0';
return result;
}
int main() {
char *result = rmchr("This is a great message to test with! It includes a lot of examples!", "i");
for (int i = 0; i < strlen(result); i++) {
printf("%c", result[i]);
}
free(result);
return 0;
}
Output:
Ths s a great message to test wth! It ncludes a lot of examples!

Segmentation fault when removing trailing whitespace from string in c

I am trying to remove the white spaces at the end of a string. I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *trim(char *str) {
char *end;
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) {
end--;
}
*(end++) = '\0'; //this line causes the segfault
return str;
}
int main(void) {
char *str = "mystring ";
printf("before trim string is %s\n", str);
printf("length before: %d\n", strlen(str)); //should be 10
str = trim(str);
printf("after trim string is %s\n", str);
printf("length after: %d\n", strlen(str)); //should be 8
return 0;
}
When I run the code, I get a segmentation fault. What I'm not sure about is why incrementing the pointer 'end' by 1, and then changing the value it points to from a white space to the null terminator causes the segfault. I have read that incrementing a pointer in C such that the pointer does not point to an element of an array is undefined behaviour. However, wouldn't the white spaces at the end of "mystring" still be part of the char array str[]? Any help is really appreciated.
The issue here is that the line causing the crash is attempting to modify a string literal, which results in undefined behavior.
According to https://en.cppreference.com/w/c/language/string_literal ,
String literals are not modifiable (and in fact may be placed in read-only memory such as .rodata). If a program attempts to modify the static array formed by a string literal, the behavior is undefined.
You'll have to make sure to pass a char* to a modifiable array, such as one you allocate yourself with malloc().
The other responses are correct - but i'm surprised your compiler did not pick up the error. Below compiles and runs fine with Visual Studio 2017.
Note a little bug also in trim()
*(++end) = '\0'; NOT
*(end++) = '\0';
All good now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *trim(char *str) {
char *end;
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) {
end--;
}
*(++end) = '\0'; //this line causes the segfault
return str;
}
int main(void) {
char str0[] = "mystring "; // minor change here
char *str = str0; // minor change here
printf("before trim string is %s\n", str);
printf("length before: %d\n", strlen(str)); //should be 10
str = trim(str);
printf("after trim string is %s\n", str);
printf("length after: %d\n", strlen(str)); //should be 8
return 0;
}
When a string is processed with a pointer, the compiler assigns the storage address of the first character of the constant string after "=" to the pointer, and the constant string exists in the read-only memory.
You can try these two code to observation difference:
int main()
{
char str[] = "abcd";
*str = 'c';
printf("%s\n", str);
return 0;
}
int main()
{
char *str = "abcd";
*str = 'c'; // error
printf("%s", str);
return 0;
}

how can i save the output of putchar to a variable

I am working on some code that filters text before it is sent further into a program (this code removes everything but all alphanumeric characters and and underscores), the code itself works perfectly except for the fact that I cannot find a way to store the output of of it for use in other parts of the program, If i had to guess, this probably involves saving the stdout from putchar into a variable, but i cannot find much info for doing so online, if someone could point me in the right direction for this I would really appreciate it, thanks!
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
int i;
char *p;
char stg[] = "hello";
for (p = &stg[0]; *p != '\0'; p++) {
if (isalnum(*p) || *p == '_') {
putchar (*p);
}
}
putchar ('\n');
return 0;
}
Perhaps I don't understand your "need" to use putchar() while doing the filtering, but you can filter the input into an output array of chars to use however needed after the filtering as shown below.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
int i;
char *p;
char stg[] = "hel123*^_lo";
char output[200] = {0x00};
int index = 0;
p = stg;
while( *p )
{
if (isalnum(*p) || *p == '_')
{
output[index++] = (char)putchar(*p);
}
p++;
}
putchar('\n');
printf("[%s]\n", output);
return 0;
}
Output:
hel123_lo
[hel123_lo]
EDIT:
And if you want to just filter the string into an array without displaying the string using putchar() you'd do something like this:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void) {
int i;
char *p;
char stg[] = "hel123*^_lo";
char output[200] = {0x00};
int index = 0;
p = stg;
while( *p )
{
if (isalnum(*p) || *p == '_')
{
output[index++] = *p;
}
p++;
}
printf("[%s]\n", output);
return 0;
}
And what exactly are you trying to do with the output of the filtered text?
putchar -- int putchar( int ch ); -- returns the character you wrote if successful, EOF if failure.
Nothing prevents you from declaring an int variable, whether a scalar variable, an array element, or a field in a struct, and saving what you wrote. Take note, the return is an int, not a char.
Based on what you've written, you'll probably have to write some code to manage all the outputs you save. In other words, if I'm interpreting your question correctly, you'll be doing more than just saving what you wrote to a variable. You'll probably want to say where in the code you executed the putchar and perhaps even the time. Just guessing though.

How to remove a carriage return from a string in C? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Remove characters from a string in C
Do you have an example of C code to remove carriage returns in a string?
The simplest solution is to probably just process the string character by character, with pointers for source and destination:
#include <stdio.h>
#include <string.h>
int main (void) {
char str[] = "This is a two-line\r\nstring with DOS line endings.\r\n";
printf("%d [%s]\n",strlen(str), str);
// ========================
// Relevant code in this section.
char *src, *dst;
for (src = dst = str; *src != '\0'; src++) {
*dst = *src;
if (*dst != '\r') dst++;
}
*dst = '\0';
// ========================
printf("%d [%s]\n",strlen(str), str);
}
This sets up two pointers initially the same. It then copies a character and always advances the source pointer. However, it only advances the destination pointer if the character wasn't a carriage return. That way, all carriage returns are overwritten by either the next character or the null terminator. The output is:
51 [This is a two-line
string with DOS line endings.
]
49 [This is a two-line
string with DOS line endings.
]
This would be adequate for most strings. If your strings are truly massive in size (or this is something you need to do many times each second), you could look at a strchr-based solution since the library function will most likely be optimised.
A carriage return or any other char is easy to replace in a string and even easier to replace. Your question does not really shows what you're looking for so I've included sample code for both removing and replacing a char in a string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void remove_char_from_string(char c, char *str)
{
int i=0;
int len = strlen(str)+1;
for(i=0; i<len; i++)
{
if(str[i] == c)
{
// Move all the char following the char "c" by one to the left.
strncpy(&str[i],&str[i+1],len-i);
}
}
}
void replace_char_from_string(char from, char to, char *str)
{
int i = 0;
int len = strlen(str)+1;
for(i=0; i<len; i++)
{
if(str[i] == from)
{
str[i] = to;
}
}
}
int main(void) {
char *original = "a\nmultiline\nstring";
int original_len = strlen(original)+1;
char *string = (char *)malloc(original_len);
memset(string,0,original_len);
strncpy(string,original,original_len);
replace_char_from_string('\n',' ',string);
printf("String: %s\n",string); // print: String: a multiline string
remove_char_from_string(' ',string);
printf("String: %s\n",string); // print: String: amultilinestring
return 0;
}

Resources