char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source) +1;
char *dest = (char*)malloc(sizeof(char)*len);
while(*source != '\0')
{
// dest[ii++] = *source++;
*dest++ = *source++;
}
// dest[ii] = '\0';
*dest = '\0';
printf("\n copied string = %s", dest1);
return dest;
}
I want to copy source string to destination string.
The above api is returning null.
If I use array of character (this I have commented) then this api works to me.
Please help me to understand the difference between
dest[ii++] = *source++
and
*dest++ = *source++;
You're incrementing dest during the while loop. You need to keep hold of a pointer to the start of the buffer to return from the function.
char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source);
char *copy = malloc(len+1);
char* dest = copy;
while(*source != '\0')
{
*dest++ = *source++;
}
*dest = '\0';
printf("\n copied string = %s", copy);
return copy;
}
Note that you could save some code by using strcpy
char *stringcopywithpointer( const char *source)
{
int len = strlen(source);
char *copy = malloc(len+1);
strcpy(copy, source);
return copy;
}
and you could reduce this to a single line if you have access to the non-standard strdup
char *stringcopywithpointer( const char *source)
{
return strdup(source);
}
My opinion:
Avoid allocate memory in called function, better allot memory before calling a function
char *dest = ( char* ) malloc( sizeof( char ) * len ); // doesn't looks great
Irrespective of the machine, sizeof( char ) is always 1 byte. Less redundant is sizeof( char ) * len. Optimal would be malloc( sizeof( source ) ).
Pointers and arrays are related
You can either use
dest[i] = src[i];
*dst++ = *src++;
or
// assuming dst memory allocate by caller
while ( *dst++ = *src++);
1)
printf("\n copied string = %s", dest1);
should be
printf("\n copied string = %s", dest);
This could be a typo
2)
You can change:
while(*source != '\0')
{
*dest++ = *source++;
}
by
while(*dest++ = *source++);
3)
Concerning difference between dest[ii++] = *source++ and *dest++ = *source++;
There is no difference and should work if dest is defined in this way
char *dest = (char*)malloc(sizeof(char)*len);
If your array is define in this way:
char dest[len];
Then there is difference
You should not return an allocated string. This can easily lead to a memory leak.
Instead you should consider passing allocated memory into your function to copy it.
You can use your return value to return an error if anything went wrong.
This would change your signature to.
int stringcopywithpointer( char * dest, const char *source)
to make your code a little bit more versitile you could implement vargs and your signature would be:
int stringcopywithpointerf( char * dest, const * format, ... );
This is actually the already existing function sprintf.
int sprintf( char * dest, const * format, ... );
There are also secure variants of the function available and premade. You may want to consider using one of those.
If this is homework related take a look at this function:
char * myscpy(const char * SRC){
size_t size = strlen( SRC ) + 1 ;
char * START;
char * DST = ( char * ) malloc( size );
START = DST;
do
{
*DST = *SRC;
DST++;
SRC++;
}while( *SRC != 0 );
*DST = *SRC;
return START;
}
You likely want to add errorchecks to it like you had them in place (malloc etc.) in your original post.
"Please help me to understand the difference between dest[i++] and *dest++"
dest[i++] does not increment the pointer but the index to the pointer.
*dest++ increments the pointer after its original contendt was accessed.
Add char *dest1 = dest; right after malloc and then return dest1 and that will work.
Other possible change: replace while loop with post-condition loop (i.e. copy the zero byte first, then check if it was the end).
may be you need to add this line
char *stringcopywithpointer( const char *source)
{
int ii = 0;
int len = strlen(source) +1;
char *ptr = NULL;
char *dest = (char*)malloc(sizeof(char)*len);
/** No Error Checking for malloc is a strict no no **/
if(dest == NULL)
return NULL;
/** hold the dest adress in ptr as we are incrementing dest **/
ptr = dest;
while(*source != '\0')
{
// dest[ii++] = *source++;
*dest++ = *source++;
}
// dest[ii] = '\0';
*dest = '\0';
//printf("\n copied string = %s", dest1); ??
printf("\n copied string = %s", ptr); // ptr will have our copied String
/** so return ptr not dest **/
return ptr;
}
Related
This is the requirement for my code:
This function appends the src string to the dest string, overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte.
Returns a pointer to the resulting string dest.
This is the output I am getting:
Hello
World!
Hello World!
Hello
Here is my code:
char *_strcat(char *dest, char *src) {
int lengthd = 0;
int lengths = 0;
int i = 0;
int j = 0;
int k = 0;
char tmp[10];
while (dest[i] != '\0') {
lengthd++;
i++;
}
while (src[k] != '\0') {
tmp[lengths] = src[k];
lengths++;
k++;
}
for (; j < lengths - 1; j++) {
dest[lengthd + 1] = tmp[j];
}
dest[lengthd + 1] = '\0';
return (dest);
}
int main(void) {
char s1[98] = "Hello ";
char s2[] = "World!\n";
char *ptr;
printf("%s\\n", s1);
printf("%s", s2);
ptr = _strcat(s1, s2);
printf("%s", s1);
printf("%s", s2);
printf("%s", ptr);
return (0);
}
Your code fails for multiple reasons:
you use a temporary array to make a copy of the source string: this array tmp has a fixed length of 10 bytes, which is too small if the source string is longer than 10 bytes. Otherwise you will have undefined behavior when you write beyond the end of this array.
there is really no need for this temporary array anyway.
the final loop stops at lengths - 1, hence you stop before the last byte of the copy.
you copy all bytes to the same position dest[lengthd + 1].
you finally set the null terminator at the same position again.
you never changed the null terminator at dest[lengthd] so the function appears to have no effect on dest.
the tests in main() cannot produce the output you posted, probably because of a typo in "%s\\n".
avoid using identifiers starting with an _.
Here is a modified version:
#include <stdio.h>
#include <string.h>
char *my_strcat(char *dest, char *src) {
int i = 0;
int k = 0;
/* find the offset of the null terminator in dest */
while (dest[i] != '\0') {
i++;
}
/* copy the bytes from the src string there */
while (src[k] != '\0') {
dest[i] = src[k];
i++;
k++;
}
/* set the null terminator */
dest[i] = '\0';
/* return the pointer to the destination array */
return dest;
}
int main(void) {
char s1[98] = "Hello ";
char s2[] = "World!";
char *ptr;
printf("%s\n", s1);
printf("%s", s2);
ptr = my_strcat(s1, s2);
printf("%s", s1);
printf("%s", s2);
printf("%s", ptr);
return 0;
}
Note that the source string is not modified and the offsets should have type size_t and can be incremented as a side effect of the assignment:
char *my_strcat(char *dest, const char *src) {
size_t i = 0;
size_t k = 0;
/* find the offset of the null terminator in dest */
while (dest[i] != '\0') {
i++;
}
/* copy the bytes from the src string there */
while (src[k] != '\0') {
dest[i++] = src[k++];
}
/* set the null terminator */
dest[i] = '\0';
/* return the pointer to the destination array */
return dest;
}
You can also use pointers instead of offsets:
char *my_strcat(char *dest, const char *src) {
/* use a working pointer to preserve dest for the return value */
char *p = dest;
/* find the offset of the null terminator in dest */
while (*p != '\0') {
p++;
}
/* copy the bytes from the src string there */
while (*src != '\0') {
*p++ = *src++;
}
/* set the null terminator */
*p = '\0';
/* return the pointer to the destination array */
return dest;
}
One final change: you can combine reading the source byte, copying to the destination and testing for the null terminator, which will have been copied already:
char *my_strcat(char *dest, const char *src) {
/* use a working pointer to preserve dest for the return value */
char *p = dest;
/* find the offset of the null terminator in dest */
while (*p != '\0') {
p++;
}
/* copy the bytes from the src string there */
while ((p++ = *src++) != '\0') {
/* nothing */
}
/* the null terminator was copied from the source string */
/* return the pointer to the destination array */
return dest;
}
At least due to the declaration of the character array tmp with the magic number 10
char tmp[10];
the function does not make a sense.
Moreover in this while loop
while (src[k] != '\0')
{
lengths++;
k++;
tmp[lengths] = src[k];
}
the first element of the array tmp is skipped.
Also in this for loop
for (; j < lengths-1; j++)
{
dest[lengthd + 1] = tmp[j];
}
the condition of the loop is incorrect. Also the expression dest[lengthd + 1] skips the terminating zero character of the string pointed to by the pointer dest. And all characters are written at the same position lengthd + 1.
Apart from this the names s1, s2 and ptr used in main were not declared.
The function can be declared and defined the following way
char * my_strcat( char *dest, const char *src )
{
char *p = dest;
while ( *p ) ++p;
while ( ( *p++ = *src++ ) != '\0' );
return dest;
}
and can be called like
char s1[13] = "Hello ";
const char *s2 = "World!";
puts( my_strcat( s1, s2 ) );
Another way to define the function using an approach similar to yours is the following
char * my_strcat( char *dest, const char *src )
{
size_t i = 0;
while ( dest[i] != '\0' ) ++i;
for ( size_t j = 0; src[j] != '\0'; j++ )
{
dest[i++] = src[j];
}
dest[i] '\0';
return dest;
}
I wrote a function to concatenate two strings (s = "computer"; t = "keyboard"), but my code only returns "keyboard". Please point out the mistakes.
char *concat(char *s, char *t) {
s = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = s;
while (*p != '\0') {
++p;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return s;
}
I do not want to use strcat(). This is a test program from Stepik, so I cannot change anything in the main function.
Here is the question: Write a function which receives two character pointers and returns a new character pointer representing their concatenation.
char *myconcat(const char *s1, const char *s2)
{
size_t len1,len2;
char *result = malloc((len1 = strlen(s1)) + (len2 = strlen(s2)) + 1);
if(result)
{
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
}
return result;
}
You have s="computer" when passed into a function, and then on the very first line you reassign it with malloc, so "computer" is gone.
You can debug your program step by step, or just print the values to the console. This will help you to find the error.
You are on the right track:
you allocate the correct amount of memory,
you copy the second string correctly,
you set the null terminator correctly,
you return the pointer to the allocated block.
Yet there are some issues:
you overwrite the pointer to the first string with that returned by malloc(),
you read from the allocated memory block instead of copying the first string: this has undefined behavior,
(minor) the argument strings should be declared as const char * as you do not modify these strings.
Here is a corrected version:
#include <stdlib.h>
#include <string.h>
char *concat(const char *s, const char *t) {
char *ret = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = ret;
while (*s != '\0') {
*p++ = *s++;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return ret;
}
I'm trying to read two consecutive characters from one string and pass two by two characters to another string. The code is below but it gives me segmentation fault! What am I doing wrong?
char *st = malloc(16*sizeof(char));
char *string = "purpleredblue";
int i;
int x=0;
while(x<=16)
{
for(i=x;i<=x+2;i++)
{
*st++=*string++; //copies content from string to st
}
x+=2;
}
printf("%s\n",st);
Your code is completely wrong. This might help:
char *buffer = (char*)malloc(16 * sizeof(char));
char *source = "purpleredblue";
char *dst = buffer;
char *src = source;
char *end = source + strlen(source);
while (src <= end)
{
strncpy(dst, src, 2);
dst += 2;
src += 2;
}
printf("%s", buffer);
I have this code made for C++ (it works):
char* ConcatCharToCharArray(char *Str, char Chr)
{
char *StrResult = new char[strlen(Str) + 2];
strcpy(StrResult, Str);
StrResult[strlen(Str)] = Chr;
StrResult[strlen(Str) + 1] = '\0';
return StrResult;
}
/* Example: String = "Hello worl"
Char = "d"
Final string = "Hello world" */
The little problem is that I'm making a standard C program in Ubuntu and I need this code.
And "new" is NOT being recognized as a reserved word and there's even a red mark under it.
I tried: char *StrResult[strlen(Str) + 2], but it doesn't work because that way only admits constant values. I'm guessing "malloc" would be the standard C solution in here, how could I do this with "malloc" or any other way for that matter? Thank you so much.
new is the C++ way of allocating memory. In C you're right, you need to use malloc.
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t len = strlen( Str );
char *StrResult = malloc( len + 2 );
/* Check for StrResult==NULL here */
strcpy(StrResult, Str);
StrResult[len] = Chr;
StrResult[len+1] = '\0';
return StrResult;
}
When you're done with the memory, you'd call free( StrResult ).
Yes, you need malloc and you are confusing C with C++ here (since new comes from C++):
char *StrResult = (*char) malloc((strlen(Str) + 2) * sizeof(char));
char takes only one byte (see this question), so you don't need to multiply by it's size:
char *StrResult = (*char) malloc(strlen(Str) + 2);
One way:
char* ConcatCharToCharArray(char *Str, char Chr)
{
size_t StrLen = strlen(Str);
char *StrResult = malloc(StrLen + 2);
if(NULL == StrResult)
goto CLEANUP;
strcpy(StrResult, Str);
StrResult[StrLen++] = Chr;
StrResult[StrLen] = '\0';
CLEANUP:
return StrResult;
}
However, the above allocates a new string, instead of concatenating a character to an existing string. Here is a way to expand an existing string with an additional character:
int StrConcatChar(char **string, char character)
{
int rCode=0;
size_t stringLen;
char *temp;
if(NULL == string)
{
rCode=EINVAL;
goto CLEANUP;
}
stringLen = *string ? strlen(*string) : 0;
errno=0;
temp=realloc(*string, stringLen+2);
if(NULL == temp)
{
rCode=errno?errno:ENOMEM;
goto CLEANUP;
}
*string=temp;
(*string)[stringLen++] = character;
(*string)[stringLen] = '\0';
CLEANUP:
return(rCode);
}
The above function might be called like this:
{
int rCode=0;
char *buffer=NULL;
buffer=strdup("Hello worl");
if(NULL == buffer)
/* handle error condition */
rCode=StrConcatChar(&buffer, 'd');
if(rCode)
/* handle error condition */
...
if(buffer)
free(buffer);
}
I've the following program:
// required include statements...
static char ***out;
char* get_parameter(char* key)
{
char *querystr = /*getenv("QUERY_STRING")*/ "abcdefg=abcdefghi";
if (querystr == NULL)
return (void*)0;
char s[strlen(querystr)] ;
strcpy(s, querystr);
const char delim = '&';
const char delim2 = '=';
static size_t size = 0;
if (out == 0)
{
out = (char*) malloc(sizeof(char*));
size = split(s, &delim, out);
}
int i=0;
for (; i<size; i++)
{
if ((*out)[i] != NULL)
{
char ***iout = NULL;
iout = (char*) malloc(sizeof(char*));
int isize = split((*out)[i], &delim2, iout);
if (isize > 1 && ((*iout)[1]) != NULL && strcmp(key, (*iout)[0]) == 0)
{
size_t _size = strlen((*iout)[1]);
char* value = (char*) malloc(_size*sizeof(char));
strcpy(value, (*iout)[1]);
free(iout);
return value;
}
}
}
return (void*) 0;
}
static size_t count(const char *str, char ch)
{
if (str == NULL) return 0;
size_t count = 1;
while (*str)
if (*str++ == ch) count++;
return count;
}
size_t split(const char *const str, const char* delim, char ***out)
{
size_t size = count(str, *delim);
*out = calloc(size, sizeof(char));
char* token = NULL;
char* tmp = (char*) str;
int i=0;
while ((token = strtok(tmp, delim)) != NULL)
{
tmp = NULL;
(*out)[i] = (char*) malloc(sizeof strlen(token));
strcpy((*out)[i++], token);
}
return size;
}
main()
{
char* val = get_parameter("abcdefg");
printf("%s\n", val); // it should prints `abcdefghi`, but it prints `abcd?`
free(val);
}
as appears in the main method, the function get_parameter should prints abcdefghi, but it prints abcd? where ? is a controls character with value of 17.
Why the reset of string is not printed? I think I mis-used the malloc to allocate appropriate space.
Also, is there any tool that I can use to know the internal representation of memory for my pointers?
You're dealing with C-Strings here. You must consider 1 additional byte for the NULL-termination ('\0')
Therefore:
char s[strlen(querystr)] ;
strcpy(s, querystr);
Is incorrect.
strlen will return 4 for string "abcd" but what you want is to allocate space for "abcd\0"
So you need strlen + 1
The lines
out = (char*) malloc(sizeof(char*));
iout = (char*) malloc(sizeof(char*));
are a problem.
sizeof() returns the number of bytes required to store an object of the given type, in this case, the size of a pointer (to a char). malloc() then allocates that many bytes (apparently 4 bytes on your architecture). To fix this, you need to give malloc the desired string length instead of using sizeof.
Additionally, the line
char* value = (char*) malloc(_size*sizeof(char));
has a completely unnecessary use of sizeof(). sizeof(char) is guaranteed by the standard to be 1.
You should use gdb to run your binary step by step and see what's wrong.
Valgrind is a very good tools, it will tell you what's line overwrite in memory, etc..