why does this pointer manipulation fail? - c

I'm working my way in understanding pointers. I wrote this string copy functionality in C.
#include<stdio.h>
char *my_strcpy(char *dest, char *source)
{
while (*source != '\0')
{
*dest++ = *source++;
}
*dest = '\0';
return dest;
}
int main(void)
{
char* temp="temp";
char* temp1=NULL;
my_strcpy(temp1,temp);
puts(temp1);
return 0;
}
This program gives a segfault.If I change char* temp1=NULL to char* temp1 still it fails. If I change char* temp1 to char temp1[80], the code works. The code also works if char temp1[1] and gives the output as temp. I was thinking the output should be t. Why is it like this and why do I get error with char* temp.

Because you're not allocating space for the destination string. You're trying to write to memory at position NULL (almost certainly 0x00).
Try char* temp1= malloc(strlen(temp)+1); or something like it. That will allocate some memory and then you can copy the characters into it. The +1 is for the trailing null character.
If you wrote Java and friends, it would prevent you from accessing memory off the end of the array. But at a language level, C lets you write to memory anywhere you want. And then crash (hopefully immediately but maybe next week). Arrays aren't strictly enforced data types, they are just conventions for allocating and referencing memory.
If you create it as char temp1[1] then you are allocating some memory on the stack. Memory near that may be accessible (you can read and write to it) but you will be scribbling over other memory intended for something else. This is a classic memory bug.
Also style: I personally advise against using the return values from ++s. It's harder to read and makes you think twice.
*dest = *source;
dest++;
source++;
Is clearer. But that's just my opinion.

You must to allocate space for the destination parameter.
When you use char temp1[80], you allocate 80 bytes in the memory.
You can allocate memory in static way, like array, or use the malloc function

Related

Can I emulate strcpy using malloc?

I'm trying to make a strcpy function from scratch for a class. While I could do it with a for loop and copy the individual characters, I think I could just make a swap using malloc and pointers to make it more efficient. Here's my code, but I've been getting a lot of confusing errors.
void notStrcpy(char s1[], char s2[]) { //copies string s1 into s2
char *s3 = (char *) malloc(strlen(s1)); //s3 is now an alias of s1
s2 = *s3;} //dereference s3 to dump s1 into s2
Why is this happening, and is there any way to make this code work the way I intended it?
You cannot do that: strcpy expects both chunks of memory to be ready - one for reading the string, and the other one for writing the string. Both addresses are expected to have enough memory for the actual content of a null-terminated C string.
On the other hand, malloc gives you a third chunk of memory (you need to allocate strlen(s)+1, but that's a completely different story). String copy algorithm has no use for that chunk of memory. On top of that, assigning parameters of a function has no effect on the values passed into your function, so s2 = *s3 is not doing what you think it should be doing.
Long story short, while ((*s1++ = *s2++)); is your simplest strcpy implementation.
Note: malloc could come in handy in an implementation of string duplication function, e.g. strdup. If you decide to give it a try, don't forget to allocate space for null terminator.
#dasblinkenlight Thank you. My new code is as follows:
void totallyNotstrcpy(char s1[], char s2[]) {
int x = 0;
while (x < strlen(s1)+1) {
s2[x] = s1[x];
x++;
}
}
As a quick side question, how does your code snippet work? Doesn't the while loop need a condition?

How to free memory allocated in a function

As in subject of this topic. I have a simple function:
char *to_str(int x)
{
char *s = malloc(6);
if (s == NULL) {
error("malloc");
}
snprintf(s, sizeof(s), "%d", x);
return s;
}
which is allocating memory in its body, and returning such value. How should I handle memory deallocation? What would be the best approach?
How should I handle memory deallocation?
Carefully. And definitely better than you do currently.
What would be the best approach?
The best approach is to free() the memory when you don't need it anymore:
char *str = to_str(1337);
// do stuff with `str'
free(str);
Also, that sizeof() is wrong. It gives you the size of a pointer, not the size of the buffer. You need to keep track of it yourself.
The calling code needs to free the memory using free():
void f(int x)
{
char *s = to_str(x);
// ...
free(s);
}
(By the way, you have a bug: in to_str, sizeof(s) is the size of a pointer, not the length of the string that s points to.)
The first of all, sizeof() is an operator that gives you a length in bytes of type (type of variable) in brackets. Thus instead of actual length of the allocated memory block, you are getting a size of the pointer s, that in common not what you expect.
The second, when you allocating the memory, you should understand the moment when it is not actually used and to make free() on it.
Also, I am not sure that 5 symbols + terminating 0 is an enough length of the string, as in case of the garbage in the x the string will be much longer, so you can corrupt the memory.
The best is not to allocate memory inside function:
char* to_str(char *buffer, size_t buffer_size, int x);
this way you don't have to care about deallocation inside the function and everything is on the caller side.
If you want to create function with the signature you have in the question, you cannot use that in anything like printf("%s", to_str(x)), because this would be a memory leak. You have to make char *str = to_str(x); printf("%s", str); free(str); which is not nice...

String copy in C causing segmentation fault

I am trying to copy a string into another char pointer variable using strcpy function.But I always get segmentation fault.Here is my code.
/* strcat example */
#include <stdio.h>
#include <string.h>
int main()
{
char str[100]="";
char *pch3;
strcpy(pch3,"Ravi");
//strcat(str,pch3); //Segmnetation fault.
puts(pch3);
return 0;
}
If I do the same thing in this one I still get segmentation fault.
else
{
misc_rec_cnt++;
fp1=fopen("breast-cancer-wisconsin-miscellaneous.data","a");
fprintf(fp1,"%s",line2);
fclose(fp1);
fp2=fopen("missingSCNs.data","a");
pch2=strtok(line2,",");
fprintf(fp2,"%s\n",pch2);
fclose(fp2);
//pch3=(char *)malloc(sizeof(char)*strlen(line3));
pch3 = strtok(line3,",");
while(pch3!=NULL)
{
if(strcmp(pch3,"?") == 0)
{
strcat(str1,"0");
strcat(str1,",");
}
else
{
//strcat(str1,pch3);
strcat(str1,",");
}
pch3 = strtok(NULL,",");
}
strlen1=strlen(str1);
memcpy(str2,str1,strlen1-1);
fp3=fopen("breast-cancer-wisconsin-miscellaneous-cleansed.data","a");
fprintf(fp3,"%s\n",str2);
fclose(fp3);
}
You need to allocate the space for pch3 before you copy to it. Use malloc to create a char array large enough to accomodate the elements of your source string before you copy it. What you are currently doing is declaring a char pointer and not initialising it. Therefore the memory location that it points to could be anywhere - and that means that you should probably not be attempting to write to it - which is why you are getting the segfault. Using malloc will allow you to allocate a region of memory that you are safe to write to and this will solve your problem (assuming the call to malloc succeeds). You cannot just go writing data to random memory locations without getting segfaults and access violations.
pch3 is a char pointer, but it doesn't have any storage associated with it which is the cause of the problem. Call malloc() to allocate some memory that the pch3 pointer can point to and you should be ok.
At this point you have a char pointer that is uninitialized and just pointing somewhere unknown. So try this:
pch3 = (char *)malloc(sizeof(char) * 100); /* 100 just as an example */
This tutorial might be helpful or this SO question: Allocating char array using malloc
pch3 is an unallocated pointer, so you're writing data to a location that doesn't exist. Did you mean to assign it to str?
char str[100]="";
char *pch3;
pch3 = str;
strcpy(pch3,"Ravi");
I'd recommend that you first allocate memory before copying data to a random place.
strcpy(pch3=(char*)malloc(sizeof("Ravi")),"Ravi");
but better check if it didn't return null pointer.

Implementing a string copy function in C

At a recent job interview, I was asked to implement my own string copy function. I managed to write code that I believe works to an extent. However, when I returned home to try the problem again, I realized that it was a lot more complex than I had thought. Here is the code I came up with:
#include <stdio.h>
#include <stdlib.h>
char * mycpy(char * d, char * s);
int main() {
int i;
char buffer[1];
mycpy(buffer, "hello world\n");
printf("%s", buffer);
return 0;
}
char * mycpy (char * destination, char * source) {
if (!destination || !source) return NULL;
char * tmp = destination;
while (*destination != NULL || *source != NULL) {
*destination = *source;
destination++;
source++;
}
return tmp;
}
I looked at some other examples online and found that since all strings in C are null-terminated, I should have read up to the null character and then appended a null character to the destination string before exiting.
However one thing I'm curious about is how memory is being handled. I noticed if I used the strcpy() library function, I could copy a string of 10 characters into a char array of size 1. How is this possible? Is the strcpy() function somehow allocating more memory to the destination?
Good interview question has several layers, to which to candidate can demonstrate different levels of understanding.
On the syntactic 'C language' layer, the following code is from the classic Kernighan and Ritchie book ('The C programming language'):
while( *dest++ = *src++ )
;
In an interview, you could indeed point out the function isn't safe, most notably the buffer on *dest isn't large enough. Also, there may be overlap, i.e. if dest points to the middle of the src buffer, you'll have endless loop (which will eventually creates memory access fault).
As the other answers have said, you're overwriting the buffer, so for the sake of your test change it to:
char buffer[ 12 ];
For the job interview they were perhaps hoping for:
char *mycpy( char *s, char *t )
{
while ( *s++ = *t++ )
{
;
}
return s;
}
No, it's that strcpy() isn't safe and is overwriting the memory after it, I think. You're supposed to use strncpy() instead.
No, you're writing past the buffer and overwriting (in this case) the rest of your stack past buffer. This is very dangerous behavior.
In general, you should always create methods that supply limits. In most C libraries, these methods are denoted by an n in the method name.
C does not do any run time bounds checking like other languages(C#,Java etc). That is why you can write things past the end of the array. However, you won't be able to access that string in some cases because you might be encroaching upon memory that doesn't belong to you giving you a segementation fault. K&R would be a good book to learn such concepts.
The strcpy() function forgoes memory management entirely, therefore all allocation needs to be done before the function is called, and freed afterward when necessary. If your source string has more characters than the destination buffer, strcpy() will just keep writing past the end of the buffer into unallocated space, or into space that's allocated for something else.
This can be very bad.
strncpy() works similarly to strcpy(), except that it allows you to pass an additional variable describing the size of the buffer, so the function will stop copying when it reaches this limit. This is safer, but still relies on the calling program to allocate and describe the buffer properly -- it can still go past the end of the buffer if you provide the wrong length, leading to the same problems.
char * mycpy (char * destination, char * source) {
if (!destination || !source) return NULL;
char * tmp = destination;
while (*destination != NULL || *source != NULL) {
*destination = *source;
destination++;
source++;
}
return tmp;
}
In the above copy implementation, your tmp and destination are having the same data. Its better your dont retrun any data, and instead let the destination be your out parameter. Can you rewrite the same.
The version below works for me. I'm not sure if it is bad design though:
while(source[i] != '\0' && (i<= (MAXLINE-1)))
{
dest[i]=source[i];
++i;
}
In general it's always a good idea to have const modifier where it's possible, for example for the source parameter.

Problem with pointer copy in C

I radically re-edited the question to explain better my application, as the xample I made up wasn't correct in many ways as you pointed out:
I have one pointer to char and I want to copy it to another pointer and then add a NULL character at the end (in my real application, the first string is a const, so I cannot jsut modify it, that's why I need to copy it).
I have this function, "MLSLSerialWriteBurst" which I have to fill with some code adapt to my microcontroller.
tMLError MLSLSerialWriteBurst( unsigned char slaveAddr,
unsigned char registerAddr,
unsigned short length,
const unsigned char *data )
{
unsigned char *tmp_data;
tmp_data = data;
*(tmp_data+length) = NULL;
// this function takes a tmp_data which is a char* terminated with a NULL character ('\0')
if(EEPageWrite2(slaveAddr,registerAddr,tmp_data)==0)
return ML_SUCCESS;
else
return ML_ERROR;
}
I see there's a problem here: tha fact that I do not initialize tmp_data, but I cannot know it's length.
For starters, you are missing a bunch of declarations in your code. For example, what is lungh? Also, I'm assuming you initialized your two pointers so they point to memory you can use. However, maybe that's not a safe assumption.
Beyond that, you failed to terminate your from string. So getting the length of the string will not work.
There seems to be numerous errors here. It's hard to know where to start. Is this really what your actual code looks like? I don't think it would even compile.
Finally, there seems to be a bit of confusion in your terminology. Copying a pointer is different from copying the memory being pointed to. A pointer is a memory address. If you simply copy the pointer, then both pointers will refer to the same address.
I would create a copy of a string using code similar to this:
char *from_string = "ciao";
char *to_string;
int len;
len = strlen(from_string);
to_string = (char *)malloc(len + 1);
if (to_string != NULL)
strcpy(to_string, from_string);
Be fully aware that you do not want to copy a pointer. You want to copy the memory that is pointed to by the pointer. It does sound like you should learn more about pointers and the memory environment of your system before proceeding too much farther.
When you say tmp_data = data, you are pointing tmp_data to the same memory pointed to by data. Instead, you need to allocate a new block of memory and copy the memory from data into it.
The standard way to do this is with malloc. If you do not have malloc, your libraries may have some other way of acquiring a pointer to usable memory.
unsigned char * tmp_data = malloc(length + 1);
if(tmp_data != 0) {
memcpy(tmp_data, data, length);
tmp_data[length] = 0;
// ...
free(tmp_data);
}
You could also use a fixed-size array on the stack:
unsigned char tmp_data[256];
if(length >= sizeof(tmp_data)) length = sizeof(tmp_data) - 1;
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;
C99 introduced variable-length arrays, which may be what you seek here, if your compiler supports them:
unsigned char tmp_data[length];
memcpy(tmp_data, data, length); // or equivalent routine
tmp_data[length] = 0;

Resources