Unable to print a pointer after using memcpy - c

I'm trying to get my own version of memcpy to copy a character array from one pointer to another. However, this gives an error. It seems like there is an issue with printf.
Secondly, the official memcpy function returns the destination pointer. Is that really required? If I modify *dest, it should be reflected in *d anyway. So what is the need to return anything?
#include <stdio.h>
void memcpy2(void *dest, const void *src, size_t n)
{
char *dp = dest;
const char *sp = src;
while (n--)
*dp++ = *sp++;
}
int main(void) {
char *c = "Hello";
char *d=NULL;
memcpy2(d,c,3);
printf( "%c", *d);
return 0;
}

You dereference a NULL pointer that's undefined behavior, you should allocate space and point to it with d in order for that to work, do this, instead of
d = NULL
write
d = malloc(3);
and don't forget
free(d);
after the printf().
If you want to automagically make d a valid pointer then write memcpy2() this way
void memcpy2(void **dest, const void *src, size_t n)
{
*dest = NULL;
if ((src == NULL) || (n == 0))
return;
*dest = malloc(n);
if (*dest == NULL)
return;
char *dp = *dest;
const char *sp = src;
while (n--)
*dp++ = *sp++;
}
and then your main would be
int main(void) {
char *c = "Hello";
char *d = NULL;
memcpy2(&d, c, 3);
/* ^ pass the address of the pointer, so you can change where it points to */
if (d != NULL) /* prevent NULL dereference. */
{
printf("%c", *d);
free(d);
}
return 0;
}

Related

How to copy char array in C without inner function

This is my code
char function(char *dst)
{
int i;
char *arr;
i = 0;
while(dst[i] != '\0')
{
arr[i] = dst[i];
i++;
}
dst[i] != '\0'
return(arr);
}
int main(void)
{
char a[] ="asdf"
printf("%s", function(a);
}
I want to copy *dst to empty *arr but my code didn't work.
I can't understand.
How can I copy array without inner function in C(ex_strcpy, memspy....)
Thank you
Apart from missing ; and making sure that the string being passed to the function is always a '\0' terminated one ( else the program will run into side effects strcpy causes ). and returning char* instead of char, you missed allocating memory for arr
// return char * instead of char
char* function(char *dst)
{
// Note - sizeof(dst) wont work
// Neither does sizeof(dst)/sizeof(char)
// allocate one extra for '\0'
size_t size_to_alloc = (strlen(dst) + 1) * (sizeof *arr);
char *arr = malloc( size_to_alloc );
char *p = arr;
for ( ; *dst ; p++, dst++)
*p = *dst;
*p = '\0';
return(arr);
}
If you want to dynamically copy an array, you'll need to allocate memory for the char array using malloc or other equivalent. Make sure you free the memory once you're done with it. I would suggest reading some posts on malloc and allocating memory in c.
This is probably a good place to start.
https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
#include <stdio.h>
#include <stdlib.h>
char* function(char *dst, size_t length) {
int i;
// Allocating the memory needed for the char array.
char *arr = (char*) malloc (sizeof(char) * length);
i = 0;
while(dst[i] != '\0') {
arr[i] = dst[i];
i++;
}
arr[length - 1] = '\0';
return(arr);
}
int main(void) {
char a[] ="asdf";
// Getting length of the array
size_t length = sizeof(a) / sizeof(a[0]);
char* val = function(a, length);
printf("%s", val);
free(val);
}
You are missing the memory allocation and basically attempting to recode strdup. See below:
char *ft_strdup(const char *src)
{
char *dst;
int len;
len = 0;
while (src[len]) // no inner function
++len;
if (!(dst = malloc(sizeof(char) * (len + 1)))) // need 1 extra char to NULL terminate.
return NULL;
dst[len] = '\0';
while (--len > -1)
dst[len] = src[len];
return dst;
}
Note that it makes sense to code your own version of strdup and include it in your program library as this function is not part of the C Standard.
If there is a possibility of copying strings without using c functions, perhaps it can be done by doing what c functions do.
it may be interesting to see what strcpy does:
https://code.woboq.org/userspace/glibc/string/strcpy.c.html
char *
STRCPY (char *dest, const char *src)
{
return memcpy (dest, src, strlen (src) + 1);
}
infact it uses memcpy: https://code.woboq.org/gcc/libgcc/memcpy.c.html
and here the magic...
void *
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}
and strlen: https://code.woboq.org/userspace/glibc/string/strlen.c.html
You can use memcpy() to copy memory directly, like in Memcpy, string and terminator and https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html In C any string has to be terminated by \0 (sentinel value)
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "World";
char destination[] = "Hello ";
/* Printing destination string before memcpy */
printf("Original String: %s\n", destination);
/* Copies contents of source to destination */
memcpy (destination, source, sizeof(source));
/* Printing destination string after memcpy */
printf("Modified String: %s\n", destination);
return 0;
}
source : https://www.educative.io/edpresso/c-copying-data-using-the-memcpy-function-in-c

Custom concat function in C with pointer

I try to code my own concatenation function in C without library, but I have issue and I don't know where it comes from.
To do my function I use pointers of char.
This is my Code :
#include <stdio.h>
#include <stdlib.h>
int longueur(char *str)
{
int i =0;
while(str[i] != '\0')
{
i++;
}
return i;
}
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = dest;
free(dest);
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
while(temp[i] != '\0')
{
dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
int main()
{
char *str1 = "World";
char *str2 = "Hello";
concat(str1, str2);
printf("-------------\n%s", str2);
return 0;
}
EDIT
I read all your answer, so I changed my concat function to :
void concat(char* source, char* dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
dest = (char*) malloc((longStr1 + longStr2)* sizeof(char) + sizeof(char));
while(dest[i] != '\0')
{
dest[i] = dest[i];
i++;
}
while(source[j] != '\0')
{
dest[i] = source[j];
i++;
j++;
}
dest[i] = '\0';
}
Now I don't have issue but my code only display "Hello"
In addition to all the good comments and solutions: realloc can give you a different pointer and you must return that pointer. So your function signature should be:
void concat(char* source, char** dest)
{
int longStr1 = (longueur(source));
int longStr2 = (longueur(dest));
int i=0, j=0;
char* temp = *dest, *temp2;
if ((temp2 = realloc(dest, ((longStr1 + longStr2)+1))==NULL) return;
*dest= temp2;
while(temp[i] != '\0')
{
*dest[i] = temp[i];
i++;
}
while(source[j] != '\0')
{
*dest[i] = source[j];
i++;
j++;
}
*dest[i] = '\0';
}
..and this assumes the function will only be called with a dest that was allocated with malloc. And sizeof(char) is always 1. (This resulting function is not optimal.)
--EDIT--
Below the correct, optimized version:
void concat(char* source, char** dest)
{
int longSrc = longueur(source);
int longDst = longueur(dest);
char *pDst, *pSrc;
if ((pDst = realloc(*dest, longSrc + longDst + 1))==NULL) return;
if (pDst != *dest) *dest= pDst;
pDst += longSrc;
pSrc= source;
while(pSrc)
*pDst++ = *pSrc++;
*pDst = '\0';
}
In your code
free(dest);
and
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
invokes undefined behavior as none of them use a pointer previously allocated by malloc() or family.
Mostly aligned with your approach, you need to make use of another pointer, allocate dynamic memory and return that pointer. Do not try to alter the pointers received as parameters as you've passed string literals.
That said, you need to have some basic concepts clear first.
You need not free() a memory unless it is allocated through malloc() family.
You need to have a char extra allocated to hold the terminating null.
Please see this discussion on why not to cast the return value of malloc() and family in C..
If your concatenation function allocates memory, then, the caller needs to take care of free()-ing the memory, otherwise it will result in memory leak.
After you have freed dest here:
free(dest);
You cannot use this pointer in following call to realloc:
dest = (char*) realloc(dest, ((longStr1 + longStr2)* sizeof(char)));
/*dest[0] = temp[0]; <------ If I do this it will generate issue, so the bellow code too*/
man realloc
void *realloc(void *ptr, size_t size);
The realloc() function changes the size of the memory block
pointed to by ptr to size bytes. (...)
But this pointer is invalid now and you cannot use it anymore. When you call free(dest), the memory dest points to is being freed, but the value of dest stays untouched, making the dest a dangling pointer. Accessing the memory that has already been freed produces undefined behavior.
NOTE:
Even if free(dest) is technically valid when called on pointer to memory allocated by malloc (it is not an error in your function to call free(dest) then), it is incorrect to use this on pointer to literal string as you do in your example (because str2 points to string literal it is an error to pass this pointer to function calling free on it).
Given your original use, perhaps you would find a variant like this useful
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
size_t longueur ( const char * str ) { /* correct type for string lengths */
size_t len = 0;
while (*str++ != '\0') ++len;
return len;
}
char * concat ( const char * first, const char * second ) {
const char * s1 = first ? first : ""; /* allow NULL input(s) to be */
const char * s2 = second ? second : ""; /* treated as empty strings */
size_t ls1 = longueur(s1);
size_t ls2 = longueur(s2);
char * result = malloc( ls1 + ls2 + 1 ); /* +1 for NUL at the end */
char * dst = result;
if (dst != NULL) {
while ((*dst = *s1++) != '\0') ++dst; /* copy s1\0 */
while ((*dst = *s2++) != '\0') ++dst; /* copy s2\0 starting on s1's \0 */
}
return result;
}
int main ( void ) {
const char *str1 = "Hello";
const char *str2 = " World";
char * greeting = concat(str1, str2);
printf("-------------\n%s\n-------------\n", greeting);
free(greeting);
return 0;
}
In this variant, the two inputs are concatenated and the result of the concatenation is returned. The two inputs are left untouched.

malloc, free, and memmove inside a subfunction

I want to use a subfunction to copy a char array. it is like this:
void NSV_String_Copy (char *Source, char *Destination)
{
int len = strlen(Source);
if (*Destination != NULL)
free(Destination);
Destination = malloc(len + 1);
memmove(*Destination, Source, len);
Destination[len] = '\0'; //null terminate
}
that way, I can call it from the main function and perform the operation this way:
char *MySource = "abcd";
char *MyDestination;
NSV_String_Copy (MySource, MyDestination);
However, it does not work as intended. please help!
C passes arguments by value, which means that you can't change the caller's MyDestination using the function prototype in the question. Here are two ways to update the caller's copy of MyDestination.
Option a) pass the address of MyDestination
void NSV_String_Copy (char *Source, char **Destination)
{
int len = strlen(Source);
if (*Destination != NULL)
free(*Destination);
*Destination = malloc(len + 1);
memmove(*Destination, Source, len);
(*Destination)[len] = '\0'; //null terminate
}
int main( void )
{
char *MySource = "abcd";
char *MyDestination = NULL;
NSV_String_Copy(MySource, &MyDestination);
printf("%s\n", MyDestination);
}
Option b) return Destination from the function, and assign it to MyDestination
char *NSV_String_Copy (char *Source, char *Destination)
{
if (Destination != NULL)
free(Destination);
int len = strlen(Source);
Destination = malloc(len + 1);
memmove(Destination, Source, len);
Destination[len] = '\0'; //null terminate
return Destination;
}
int main( void )
{
char *MySource = "abcd";
char *MyDestination = NULL;
MyDestination = NSV_String_Copy(MySource, MyDestination);
printf("%s\n", MyDestination);
}

How to use malloc in this situation?

I'm a bit of a newbie at C, so please bear with me...
I have a function to count char in a string called char strLength, but I have to create a function that uses this function to count the number of characters in a passed string, mallocates a new string with space for a NULL terminator, copies the string and then returns the copy.
Here's what I have:
character counter
int strLength(char* toCount)
{
int count = 0;
while(*toCount != '\0')
{
count++;
toCount++;
}
return count;
}
and here's the beginning of the sought-after function
char* strCopy(char *s)
{
int length = strLength(s);
}
Since you are struggling with malloc, here is how the next line should look:
char* strCopy(char *s)
{
int length = strLength(s);
char *res = malloc(length+1);
// Copy s into res; stop when you reach '\0'
...
return res;
}
You want strdup. However, since I suspect this is a learning exercise:
char *strCopy(const char *src)
{
size_t l = strlen(src) + 1;
char *r = malloc(l);
if (r)
memcpy(r, src, l);
return r;
}
If you are curious how to copy strings yourself, you could replace the memcpy with something like:
char *dst = r;
while (*src)
*dst++ = *src++;
*dst = 0;
However I would suggest using library functions: if not strdup, then malloc + memcpy.
You can use strdup() clib call.
You can write something like:
char* strCopy(char *s) {
int length = strLength(s);
char *rc = (char *)malloc(length + 1);
return rc? strcpy(rc, s) : NULL;
}

qsort() sorts one array of strings but segfaults on another one

I'm trying to read a bunch of names from a .txt file and copying them to an array as I go. I then want to sort the array using qsort(). Also, the file I'm reading is names.txt from Project Euler #22. Here is the code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
/* create a pointer to point to s */
char *strdup(char *s)
{
char *p;
p = (char *) malloc(strlen(s)+1);
if (p != NULL)
strcpy(p, s);
return p;
}
int compare(const void *a, const void *b)
{
const char *ap = *(const char **) a;
const char *bp = *(const char **) b;
return strcmp(ap, bp);
}
int main(void)
{
FILE *fp;
int c, i, j=0;
char name[100], *names[10000];
fp = fopen("names.txt", "r");
if (fp == NULL) {
printf("can't open file\n");
exit(0);
}
c = fgetc(fp); /* initialize c and skip first quotation mark */
while (c != EOF) { /* loop until no names are left */
i = 0;
while ((c=fgetc(fp)) != '"') /* copy chars to name until " is reached */
name[i++] = c;
name[i] = '\0';
names[j++] = strdup(name);
fgetc(fp); /* skip comma */
c = fgetc(fp);
}
size_t size = sizeof(names[0]);
size_t count = sizeof(names)/size;
qsort((void **) names, count, size, &compare);
return 0;
}
Trying to sort the names array causes a segfault. However, if I instead try to sort an array of strings that is explicitly declared it works:
char *test[] = { "FOO", "BAR", "TEST" };
size_t size = sizeof(test[0]);
size_t count = sizeof(test)/size;
qsort((void **) test, count, size, &compare);
for (i = 0; i < 3; ++i)
printf("%s\n", test[i]);
return 0;
I suspect that the segfault is due to an error in my array "names", but if I loop through and print each element of "names" before trying to sort it does so without a problem.
Any help is much appreciated!
This line:
size_t count = sizeof(names)/size;
Will yield the entire length of your names array, not just the values you have initialized. If you entered fewer than 10000 names, you're going to have some invalid pointers in there, and when you try to sort them - KABOOM!
You can just use j instead of count, since you're using that to keep track of how many names have been input.
You are missing to initialise names.
The easiest way to do so is like this:
names[10000] = {NULL};
Also the compare function is not prepared to handle the unused entries, you could modify it like this, treating unused entries like emtpy entries.
int compare(const void *a, const void *b)
{
const char *ap = a ?*(const char **) a :"";
const char *bp = b ?*(const char **) b :"";
return strcmp(ap, bp);
}
Alternativly you could sort all unused entries to the end:
int compare(const void *a, const void *b)
{
if (*a && *b)
{
const char *ap = a ?*(const char **) a :"";
const char *bp = b ?*(const char **) b :"";
return strcmp(ap, bp);
}
else
{
if (*a)
return -1;
else (*b)
return 1;
return 0;
}
}
Also you are telling qsort() to always inspect all of names's entries. Which is is unnecessary.

Resources