Why is the last output "eU2"?
#include<stdio.h>
#include<string.h>
void main()
{
char str1[] = "See the stone set in your eyes";
char str2[] = "U2";
char* ptr;
ptr = &str1[3];//the stone...
printf("%d\n", str1 - ptr); // -3
ptr[-1] = 0;// del s
ptr = (++ptr)+1;
printf("%s\n", ptr); // he stone set in your eyes
strcpy(ptr, str1+1); // ee the stone set in your eyes
strcat(ptr-2, str2);
printf("%s\n", ptr);
}
I wrote notes next to lines I understood
Based on Steve Summit's comments, I replaced ptr = (++ptr)+1, which leads to undefined behavior, with two repetitions of ptr++.
#include<stdio.h>
#include<string.h>
int main(void)
{
char str1[] = "See the stone set in your eyes";
char str2[] = "U2";
char* ptr;
ptr = &str1[3];// points at the space before "the stone..."
printf("%ld\n", str1 - ptr); // -3
ptr[-1] = 0; // replaces the second e of see with 0 in str1
ptr++;
ptr++; // points to the h of "the stone..."
printf("%s\n", ptr); // he stone set in your eyes
strcpy(ptr, str1+1); // ptr points to "e\0 the stone set in your eyes"
strcat(ptr-2, str2); // concatenates the string "e\0" with "U2\0"
printf("%s\n", ptr); // prints eU2
}
Related
I want to test pass pointer by reference in C, below is my test code.
I expect the result to be: "World!", but after I executed, I found that the result is indeterminate.
void parse(char **p)
{
char str[] = "Hello World!";
char *token = strtok(str, " "); // token points to 'H'
*p = strtok(NULL, " "); // *p (buf) points to 'W'
}
int main()
{
char *buf = (char*)malloc(20 * sizeof(char));
buf = "How are you?";
parse(&buf);
printf("%s\n", buf);
}
My View:
(1) In main(): buf points to 'H' ("How are you?"'s first char 'H') (Suppose address of 'H' is 0x10)
(2) parse(&buf) makes pointer p points to buf (i.e. *p = buf = 0x10)
(3) After 2 times of strtok(), *p (buf) points to 'W' (Suppose address of 'W' is 0x20)
(4) Now, return to main(), buf points to 0x20
(5) I expect printf("%s\n", buf); should print "World!", but instead print something like "garbled text".
I have tried debugging, but I don't think I have mistaken anything above.
Can someone quell my doubts?
Thanks in advance.
This code snippet
char *buf = (char*)malloc(20 * sizeof(char));
buf = "How are you?";
produces a memory leak.
At first memory was dynamically allocated and its address was assigned to the pointer buf and then the pointer was reassigned with the address of the first character of a string literal. As a result the address of the allocated memory was lost.
Also you may not change a string literal. Any attempt to change a string literal results in undefined behavior,
You should write at least
strcpy( buf, "How are you?" );
As for the function then its local array with automatic storage duration
void parse(char **p)
{
char str[] = "Hello World!";
//...
will not be alive after exiting the function. So the pointer buf will have an invalid value.
The program can look for example the following way
#include <stdio.h>
#include <string.h>
void parse( char *s, char **p)
{
*p = strtok( s, " " );
*p = strtok(NULL, " ");
}
int main()
{
char str[] = "Hello World!";
char *buf;
parse( str, &buf );
if ( buf ) printf("%s\n", buf);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
char *str;
/* Initial memory allocation */
str = (char *) malloc(15);
strcpy(str, "tutorialspoint");
printf("String = %s, Address = %u\n", str, str);
/* Reallocating memory */
str = (char *) realloc(str, 25);
strcat(str, ".com");
printf("String = %s, Address = %u\n", str, str);
/* Deallocate allocated memory */
free(str);
printf("\n%d",*str);
return(0);
}
Your last print says to print the character pointed to by str as a decimal, which is exactly what it did (for a memory location you just deallocated, making this undefined behavior).
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;
}
I'm basically just taking a string and appending / concatting with another string. The first run through produces the desired results, but the 2nd, 3rd and so on results seem to be doubling the src string. Combining things with jQuery is super simple, not sure whats going on here in C. Should I be using memset? or calloc?
#include <stdio.h>
#include <string.h>
int main(void) {
const char* name = "Michelle";
char *ptr;
char dest[30];
char yourName[30];
char dots[] = "..";
int i;
for (i=0;i<4;i++)
{
if (strlen(name) > 5)
{
sprintf(yourName, "%s", name);
strncpy(dest, yourName, 3);
ptr = strcat(dest, dots);
sprintf(yourName, "%s", ptr);
printf("%s\n", yourName);
}
}
return 0;
}
I'm expecting to see results such as
Michelle becomes Mic..
This works, however if my name structure has 4 names and they were all Michelle the results are...
Mic..
Mic....
Mic......
Mic........
You didn't heed the following warning:
The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
Replace
ptr = strncpy(dest, yourName, 3);
strcat(dest, dots);
sprintf(yourName, "%s", ptr);
with
ptr = strncpy(dest, yourName, 3);
dest[3] = '\0';
strcat(dest, dots);
sprintf(yourName, "%s", ptr);
or just
yourName[3] = '.';
yourName[4] = '.';
yourName[5] = '\0';
2 strings are given, second word will be append to first one and 3rd variable will store this. For example;
char *str1 = "abc";
char *str2 = "def";
char *str3 = "abcdef"; //should be
Here is my code, I get runtime error:
#include <stdio.h>
#include <malloc.h>
void append(char *str1, char *str2, char *str3, int size1, int size2)
{
int i=0;
str3 = (char*) malloc(size1+size2+1);
str3 = str1;
while (str2[i] != '\0') {
str3[i+size1] = str2[i];
i++;
}
str3[size1+size2] = '\0';
}
int main()
{
char *str1 = "abc";
char *str2 = "def";
char *str3;
append(str1, str2, str3, 3, 3);
return 0;
}
str3 = (char*) malloc(size1+size2+1);
str3 = str1;
Here's your problem. Doing this replaces the pointer to the correct amount of space from malloc to the pointer where str1 is contained. Keeping with your loop design, change this to:
str3 = malloc(size1+size2+1);
for (int j = 0; str1[j] != '\0'; j++)
str3[j] = str1[j];
Also, see this question/answer about casting the result of malloc in C:
Do I cast the result of malloc?
There is another issue with the code. You pass pointer by value. So any malloc inside a function will do only local changes. After function ends your pointer will still point to the old value. You should pass a pointer to pointer if you want to change it. See an example:
#include <stdio.h>
char *c = "Second";
void assign(char *s) { s = c; }
int main()
{
char *str = "First";
assign(str);
printf("String after assign: %s\n", str);
return 0;
}
After running the program you will see 'First' in you console. The correct code is:
#include <stdio.h>
char *c = "Second";
void assign(char **s) { *s = c; }
int main()
{
char *str = "First";
assign(&str);
printf("String after assign: %s\n", str);
return 0;
}
#include <stdio.h>
#include <stdlib.h> //to standard
#include <string.h>
char *append(const char *str1, const char *str2, int size1, int size2){
//parameter char *str3 is local variable.
//It is not possible to change the pointer of the original.
//str3 = str1;//<<-- memory leak
//str3[i+size1] = str2[i];//<<-- write to after str1(can't write!)
char *str3 = (char*) malloc(size1+size2+1);
memcpy(str3, str1, size1);//copy to alloc'd memory.
memcpy(str3 + size1, str2, size2);//copy to after str1
str3[size1+size2] = '\0';
return str3;
}
int main(){
char *str1 = "abc";
char *str2 = "def";
char *str3;
str3 = append(str1, str2, 3, 3);
printf("%s\n", str3);
return 0;
}