This is a really mysterious behavior I can't get around.
I'm trying to edit the string of one variable and then copy again to the source. I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char word[100] = "1 hash";
char* sp = malloc(100);
sp = strchr(word, ' ');
sp++;
// the "bug" still happens with strcpy instead of strncpy
strncpy(word, sp, 100);
printf("%s\n", word);
}
The output is:
hhsh
It should've been hash.
The weird thing is that "1 hash" is the only string I found that this bug happens. All the other strings I tried gave me the expected output. For example: "1 huhanh" -> huhanh or "3 a h c" -> a h c
Any help would be greatly appreciated.
You have undefined behavior. The malloc pointer is ignored.
So, when you do the strcpy, sp and word are part of the same string.
This is UB. Which means it may segfault. It may work. It may produce incorrect results.
In this instance, we can't predict the order of the fetching of the bytes and the storing. With certain sequences, it will [appear to] work. With others, we may fetch a byte that was not an input but an output from the previous byte.
Here is the corrected code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main()
{
char word[100] = "1 hash";
char *copy = malloc(100);
char *sp = strchr(word, ' ');
sp++;
strncpy(copy, sp, 100);
printf("%s\n", copy);
}
UPDATE:
Thanks for the answer. I indeed didn't realized they were all part of the same string. In the example code u provided, does the pointer sp still have to exist? –
Pedro Vinícius
Yes, because it is where you are copying from. Notice that you get the pointer from strchr. Then, you increment it. It is this updated value that becomes the source address.
This is clean code.
But, you could do:
strncpy(copy, strchr(word, ' ') + 1, 100);
But, I wouldn't do this. IMO, it's "too cute". The original sp code will execute just as fast. And, it's easier to read. And it let's you do some error checking:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main()
{
char word[100] = "1 hash";
char *copy = malloc(100);
char *sp = strchr(word, ' ');
if (sp != NULL) {
sp++;
strncpy(copy, sp, 100);
}
else
*copy = 0;
printf("%s\n", copy);
}
char* sp = malloc(100);
The problem is that this allocated memory is not used, at all. strchr returns a pointer to a character in the original string. And according to the documentation
destination and source shall not overlap
this code
char* sp = malloc(100);
sp = strchr(word, ' ');
allocates some memory then leaks it away. sp ends up pointed into the 'word' on the stack
Related
The code is supposed to print out 13:Hello World!, but the output is only 13:.
#include <stdio.h>
int main(){
char *str = "Hello World!\n";
int Laenge= 0;
while (*str++){
++Laenge;
}
printf(" %d:%c\n", Laenge, *str);
return 0;
}
You set str to point to the beginning of the string, and then you increment str till you get to the end. By that time, str is now pointing to the end of your string.
Try using a different pointer to walk through your string, or just save a copy of the pointer for later use.
It also looks like you're syntax is wrong for the print statement. I haven't coded in C for decades. I'm a Python user now. But I think *str would reference one char, and you want to reference the entire string. So if str was not corrupted, use %s and str instead of %c and *str in your printf().
You can interate till you find the null character!
#include <stdio.h>
int main()
{
char *str = "HELLO WORLD!\n";
int len = 0;
while(*(str + len) != '\0'){
len++;
}
printf("%d:%s", len, str);
return 0;
}
Your code is not working because your are incrementing the original string and converting it to '\0'. Use a walker.
you need to remeber the original str pointer
you should printf str not *str
#include <stdio.h>
int main(){
char *str = "Hello World!\n";
char *temp = str;
int Laenge= 0;
while (*temp++){
++Laenge;
}
printf(" %d:%c\n", Laenge, str);
return 0;
}
The code is only supposed to do what it has been programmed to do, to the letter of the law. Unfortunately, what's written doesn't always coincide with what the programmer intended the program to do.
In the while loop, you increment str until you reach the end, at which point the while loop ends. Now the pointer points to the end of the string.
Other than that, the format specifier for a string is %s, not %c. The %c would only print a single character. Change *str to str, unless you want to print a single character, but then you mentioned the expected output is supposed to be Hello, World.
Note:
Do not post text as an image. Post text as text, one can't copy and paste your code from an image. It's difficult to see where the problem may be arising from, and hence is difficult to debug.
I have an array of char and I'm trying to have a string literal with the same chars in the array.
I tried strcpy, and try =, and I tried what I did in the following code. But it doesn't seem to work or I'm understanding something.
char s1[10]="Youssef";
char *s2
while(*s2!='\0')
*s2++=*s1++;
printf("%s",s2);
Process doesn't return.
String literals are read only.
In any case, what you are trying to do seems you are confused.
A string literal: char *sl = "string literal";
An uninitialized char pointer: char *s2;
In order to do the copy you like, you first need to allocate memory for the string.
Moreover, you cannot do pointer arithmetics with an array. Arrays and pointers are not the same thing!
Furthermore, you should remember the origin of s2 pointer, since after incrementing it until the copy is complete, you would then need to reset the pointer.. Exercise: Think what would happen if you did the copy in a function (preferably named mystrcpy`)...
Complete example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char s1[10]="Youssef";
char *s2 = malloc(sizeof(char) * (strlen(s1) + 1)); // +1 for the NULL-terminator
int i = 0;
char *origin_s2 = s2;
while(s1[i] != '\0')
*s2++ = s1[i++];
*s2 = '\0';
s2 = origin_s2;
printf("%s\n", s2);
return 0;
}
Output:
Youssef
PS: It is highly recommended to check if the dynamic allocation of the memory was successful (check if return value of malloc() is not NULL).
I'm trying to figure out why this doesn't work.
I'd like to take data from a file using the 'getline()' function and convert the string so that the slashes ('/') that are not in quotes are replaced with new line characters. I'd like to avoid copying the string to another if possible.
I tried my program below, with two attempts to process the same data. The first attempt wasn't quite right. I expected to see the following in both cases:
ABC
DEF'/'GH
But
printf("%s",newline);
only returns this:
ABC
DEF'/'
and:
printf("%s",newline2);
returns a segmentation fault.
Because the getline() function returns the string as a char array with memory pre-allocated to it, I feel a ridiculous solution would be:
char lines[5000000];
strcpy(lines,datafromgetline);
char* newline=parsemulti(lines,10); //prints data almost correctly
printf("%s",newline);
But could I somehow do this where I don't have to allocate local stack space or memory? Can I somehow modify the incoming data directly without a segmentation fault?
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
// replaces all occurrences of / not within single quotes with a new line character
char* parsemulti(char* input,int inputlen){
char* fms=strchr(input,'/');
char output[100000]; //allocate tons of space
if (!fms){
return input;
}else{
int exempt=0,sz=inputlen;
char aline[5000];
char*inputptr=input,*lineptr=aline;
memset(aline,0,5000);
while(--sz >= 0){
if (*inputptr=='\''){exempt=1-exempt;} //toggle exempt when ' is found
if (*inputptr=='/' && exempt==0){
*lineptr='\0';
strcat(output,aline);
lineptr=aline;
strcat(output,"\r\n");
}else{
*lineptr=*inputptr;lineptr++;
}
inputptr++;
}
if (exempt==1){printf("\nWARNING: Unclosed quotes\n");}
*lineptr='\0';
strcat(output,aline);
strcat(output,"\r\n");
}
strcpy(input,output);
return input;
}
int main(){
char lines[5000];
strcpy(lines,"ABC/DEF'/'GH");
char* newline=parsemulti(lines,10); //prints data almost correctly
printf("%s",newline);
char* lines2="ABC/DEF'/'GH";
char* newline2=parsemulti(lines2,10); //returns segmentation fault
printf("%s",newline2);
return 0;
}
Two lines
char lines[5000];
strcpy(lines, "ABC/DEF'/'GH");
will
allocate memory for 5000 objects of type char on stack
copy string literal contents to memory pointed by name "lines", which you can modify
on the other hand
char *lines2 = "ABC/DEF'/'GH";
defines pointer to string literal that is usually located in read only memory.
Read only, as in do not modify me :)
You tagged this C so I assume You are talking about using getline() function - not a part of C standard, but provided by GNU C Library, that manages memory on it's own (so basically it can, and will do memory allocations, unless you preallocate it. It uses only heap memory, so if preallocated size is too small it reallocates it. Thus You can't provide address to stack char array instead).
To actually find and replace escape character from string, I'd say you should not reinvent wheel and use library string functions.
char *line = NULL;
char *needle;
ssize_t line_size;
size_t size = 0;
line_size = getline(&line, &size, stdin);
while (line_size != -1) {
needle = strchr(line, '/');
while (needle) {
if (needle != line && !(*(needle - 1) == '\'' && *(needle + 1) == '\''))
*needle = '\n';
needle = strchr(needle + 1, '/');
}
printf("%s", line);
line_size = getline(&line, &size, stdin);
}
If i have char* str; how do I write a function that accepts str and can make changes to str so that, the changes persist after the function returns?
what I have is:
char *str = (char *) malloc(10);
sprintf(str, "%s", "123456789");
//str points to 1
move_ptr(&str);
//str points to 2
void move_ptr(char** str)
{
*str++;
}
is there a better way to do that?
Just access the data through the pointer, in the function:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
void change_string(char *str)
{
size_t i;
/* As an example, make it all upper case. */
for(i = 0; str[i]; ++i)
str[i] = toupper(str[i]);
}
int main(void)
{
char buffer[32];
char *str = buffer;
strcpy(str, "test string");
change_string(str);
printf("it's now %s\n", str);
return EXIT_SUCCESS;
}
Come to think of it, you'll notice that the standard strcpy() function is exactly of the category you describe. It's a very common operation in C.
UPDATED: The question has been significantly rewritten, now it seems to be more about changing the pointer itself, rather than the data. Perhaps this was the meaning all along, but I didn't understand.
The solution in the question is fine, but personally I find it more convenient to work with return values, if possible:
char * change_pointer(char *str)
{
return str + 1;
}
int main(void)
{
char *str = "test string";
printf("now '%s'\n", str);
str = change_pointer(str);
printf("now '%s'\n", str);
return EXIT_SUCCESS;
}
The pointer(s) could of course also be const-declared, and should be if no changes to the buffered text are needed.
Question changed
If your pointer points to readonly data, you can't change what it points to.
When one writes
char *data = "forty two";
that "forty two" is readonly data; and you can't change what the pointer data points to whether directly or through a function call.
To get a 'string' initialized from a literal constant, instead of assigning a pointer to the literal constant, copy the characters to an array
char data[] = "forty two";
Now data is an array of 10 characters (9 for the letters and space + 1 for the NUL terminator) which you can change at will.
Your example may be over simplified, but just in case... Be careful of doing things like this because you're going to leak memory. After your function call, you no longer have a pointer to (part of) the original memory you allocated.
As mentioned by unwind, returning the new pointer may be a better choice. While it achieves the same goal, it makes it more obvious that you need to keep the original pointer around for the purposes of releasing the memory. The counter argument being that it gives the impression that you can free the original pointer once you have the return value, which you can't do because they both point at (different locations) in the same memory block.
I've tried reinventing the strcpy C function, but when I try to run it I get this error:
Unhandled exception at 0x00411506 in brainf%ck.exe: 0xC0000005: Access violation writing location 0x00415760.
The error occurs in the *dest = *src; line. Here's the code:
char* strcpy(char* dest, const char* src) {
char* dest2 = dest;
while (*src) {
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return dest2;
}
EDIT: Wow, that was fast. Here's the calling code (strcpy is defined in mystring.c):
#include "mystring.h"
#include <stdio.h>
int main() {
char* s = "hello";
char* t = "abc";
printf("%s", strcpy(s, t));
getchar();
return 0;
}
char* s = "hello";
char* t = "abc";
printf("%s", strcpy(s, t));
The compiler placed your destination buffer, s, in read-only memory since it is a constant.
char s[5];
char* t = "abc";
printf("%s", strcpy(s, t));
Should fix this problem. This allocates the destination array on the stack, which is writable.
The obvious potential problem is that your output buffer doesn't have enough memory allocated, or you've passed in NULL for dest. (Probably not for src or it would have failed on the line before.)
Please give a short but complete program to reproduce the problem, and we can check...
Here's an example which goes bang for me on Windows:
#include <stdlib.h>
char* strcpy(char* dest, const char* src) {
char* dest2 = dest;
while (*src) {
*dest = *src;
src++;
dest++;
}
*dest = '\0';
return dest2;
}
void main() {
char *d = malloc(3);
strcpy(d, "hello there this is a longish string");
}
Note that in this case I had to exceed the actual allocated memory by a fair amount before I could provoke the program to die - just "hello" didn't crash, although it certainly could depending on various aspects of the compiler and execution environment.
Your strcpy() is fine. You are writing to read-only memory. See this description here.
If you had written this, you'd be fine:
#include "mystring.h"
#include <stdio.h>
int main() {
char s[] = "hello";
char t[] = "abc";
printf("%s", strcpy(s, t));
getchar();
return 0;
}
There is a problem with calling of your reinvented strcpy routine in the main routine, both character array:
char* s = "hello";
char* t = "abc";
will land into memory READ ONLY segment at compile time. As you're trying to write to memory pointed by s in the routine strcpy, and since it points to a location in a READ ONLY segment, it will be caught, and you'll get an exception. These strings are READ ONLY!
Make sure dest has it's memory allocated before calling that function.
Probably an issue with the caller: did you check the dest pointer? Does it point to something valid or just garbage? Besides that, the least you could do is check for null pointers, like if (!dest || !source) { /* do something, like return NULL or throw an exception */ } on function entry. The code looks OK. Not very safe, but OK.
There are several errors.
You don't allocate a return buffer that can hold the copied string.
You don't check to see if src is null before using *src
You are both tring to get the answer in a parameter and return the value. Do one or the other.
You can easily overrun the dest buffer.
Good luck.
when ever the code starting execution(generaly it starts from main function). here the code means sequence of execution.so, when the process(sequence of execution) starts , the PCB(process control block) is created,the pcb having complete infromation about the process like process address space,kernal stack,ofdt table like this.
in your code
char* s = "hello";
char* t = "abc";
this is the what you have taken inputs of two strings like this.
here, the the strings(which means double quoted) which are present in text section of the process address space . here text section is the one of the section which is present in the process address space and text section only having the permissions of read-only. that is why when you trying to modify the source string/destination string, we MUST NOT allowable to change the whatever data is present in the text setion. so, this is what the reason for your code you need to be CAUTIOUS. hope you understand.