I'm having probs with an own function that should make str2 copied to str1 based on the amount of characters.
char * strncpy_own(char * str1, char * str2, int c)
{
int i;
for( i = 0; i < c; i++, str1++, str2++ )
{
*str1 = *str2;
}
*(str1 + 1) = '\0';
return str1;
}
Please help, When it starts it immediately terminates and says: CLearningsss has stopped working ( my name of the project ).
It should be
*str1 = '\0';
since it has already been incremented.
In a simplified version
while (c-- > 0) *str1++ = *str2++;
you can easily see that when c is 1, *str1 gets *str2 value, and is incremented, thus str1 is pointing after the value that has just been set. Thus using directly str1 pointer to set the final 0 to indicate the end of the string can be written as
while (c-- > 0) *str1++ = *str2++;
*str1 = 0;
(actually '\0' represents a char value of zero, thus writing directly 0 works as well)
Also, (thanks to #Guillaume_Morin for mentioning that) the function should better return a pointer to the beginning of the result string (str1), and you need to keep a copy of the initial str1 for that, since it is incremented later on:
char * strncpy_own(char * str1, char * str2, int c) {
char *str1copy = str1;
while (c-- > 0) *str1++ = *str2++;
*str1 = 0;
return str1copy;
}
Did you allocate the memory for str1 and str2 in advance? You need c + 1 bytes for each string; c + 2 for the mutated string given the bug you have that another answer has pointed out;-)
char *strncpy_my(char *str1, char *str2, size_t size){
char *ret = str1;
while(size>0){
if(*str2=='\0')break;
*str1++ = *str2++;
--size;
}
while(size>0){
*str1++ = '\0';
--size;
}
return ret;
}
Related
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;
}
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}else{
printf("Error");
}
return copy;
}
int main(int argc, char * argv[]){
char str[] = "Input string";
char * input;
input = removeChar(str,'g');
printf("%s\n", input);
free(input);
return 0;
}
I don't know why every time I try to run it ,it always says uninitialized variable and sticks in the strcpy line and printf line.
Basically this function is to take a string, and a character and removes the that character from the string (because I am learning malloc so that's why I wrote the function like this).
After the while loop do:
copy[j] = '\0';
to NULL-terminate your string; that way it can work with methods coming from <string.h>, which assume that the string is nul-terminated.
PS: One warning you should see is about not returning copy in your function in any case, because now if the condition of the if statement is wrong, your function won't return something valid, so add this:
return copy;
at the end of your function (which is now corrected with your edit).
Other than that, the only warning you should still get are for the unused arguments of main(), nothing else:
prog.c: In function 'main':
prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char * argv[]){
^~~~
While you copy over bytes from str to copy, you don't add a terminating null byte at the end. As a result, strcmp reads past the copied characters into unitialized memory, possibly past the end of the allocated memory block. This invokes undefined behavior.
After your while loop, add a terminating null byte to copy.
Also, you never return a value if the if block at the end is false. You need to return something for that, probably the copied string.
char * removeChar(char * str, char c){
int len = strlen(str);
int i = 0;
int j = 0;
char * copy = malloc(sizeof(char) * (len + 1));
while(i < len){
if(str[i] != c){
copy[j] = str[i];
j++;
i++;
}else{
i++;
}
}
// add terminating null byte
copy[j] = '\0';
if(strcmp(copy, str) != 0){
strcpy(str,copy);
}
// always return copy
return copy;
}
You never initialised input and the some compilers don't notice,
that the the value is never used before the line
input = removeChar(str, 'g');
in your code. So they emit the diagnostic just to be sure.
strcpy(str, copy)
gets stuck in your code, as copy never got a closing 0 byte and
so depends on the nondeterministic content of your memory at the
moment of the allocation of the memory backing copy, how long strcpy
will run and if you get eventually a SIGSEGV (or similar).
strcpy will loop until it finds a 0 byte in your memory.
For starters to remove a character from a string there is no need to create dynamically a character array and then copy this array into the original string.
Either you should write a function that indeed removes the specified character from a string or a function that creates a new string based on the source string excluding the specified character.
It is just a bad design that only confuses users. That is the function is too complicated and uses redundant functions like malloc, strlen, strcmp and strcpy. And in fact it has a side effect that is not obvious. Moreover there is used incorrect type int for the length of a string instead of the type size_t.
As for your function implementation then you forgot to append the terminating zero '\0' to the string built in the dynamically allocated array.
If you indeed want to remove a character from a string then the function can look as it is shown in the demonstrative program.
#include <stdio.h>
char * remove_char(char *s, char c)
{
char *p = s;
while (*p && *p != c) ++p;
for ( char *q = p; *p++; )
{
if (*p != c) *q++ = *p;
}
return s;
}
int main( void )
{
char str[] = "Input string";
puts(str);
puts(remove_char(str, 'g'));
return 0;
}
The program output is
Input string
Input strin
If you are learning the function malloc and want to use it you in any case should try to implement a correct design.
To use malloc you could write a function that creates a new string based on the source string excluding the specified character. For example
#include <stdio.h>
#include <stdlib.h>
char * remove_copy_char(const char *s, char c)
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p != c) ++n;
}
char *result = malloc(n + 1);
if (result)
{
char *q = result;
for (; *s; ++s)
{
if (*s != c) *q++ = *s;
}
*q = '\0';
}
return result;
}
int main( void )
{
char *str = "Input string";
puts(str);
char *p = remove_copy_char(str, 'g');
if ( p ) puts(p );
free(p);
return 0;
}
The program output will be the same as above.
Input string
Input strin
Pay attention to the function declaration
char * remove_copy_char(const char *s, char c);
^^^^^^
In this case the source string can be a string literal.
char *str = "Input string";
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;
}
I am writing a C program in Unix and cannot figure out how to set an array element to NULL. I need to be able to do this to remove multiple characters from a string.
You can't assign null to specific char array index as value represented by that index is char instead of pointer. But if you need to remove specific character from given string, you can implement this as follows
void removeChar(char *str, char garbage) {
char *src, *dst;
for (src = dst = str; *src != '\0'; src++) {
*dst = *src;
if (*dst != garbage) dst++;
}
*dst = '\0';
}
Test Program
#include<stdio.h>
int main(void) {
char* str = malloc(strlen("abcdef")+1);
strcpy(str, "abcdbbbef");
removeChar(str, 'b');
printf("%s", str);
free(str);
return 0;
}
output
acdef
If you have a char[], you can zero-out individual elements using this:
char arr[10] = "foo";
arr[1] = '\0';
Note that this isn't the same as assigning NULL, since arr[1] is a char and not a pointer, you can't assign NULL to it.
That said, that probably won't do what you think it will. The above example will produce the string f, not fo as you seem to expect.
If you want to remove characters from a string, you have to shift the contents of the string to the left (including the null terminator) using memmove and some pointer arithmetic:
Example:
#include <stdio.h>
#include <string.h>
int removechars(char *str, size_t pos, size_t cnt) {
size_t len = strlen(str);
if (pos + cnt > len)
return -1;
memmove(str + pos, str + pos + cnt, len - pos - cnt + 1);
return 0;
}
Then use it like so:
char str[12] = "hello world";
if (removechars(str, 5, 4) == 0) /* remove 4 chars starting at str[5] */
printf("%s\n", str); /* hellold */
If you're talking about an array of pointers (say char **), you'd just say array[element] = NULL;. But it sounds as though you really want to just truncate a string (char *), in which case you'd actually want to write string[index] = '\0', where \0 is the null byte. But, as far as I know, 0, '\0', and NULL are all equivalent and equal to 0 (please correct me if I'm wrong). Of course, for clarity, you should use 0 for numbers, '\0' for chars and strings, and NULL for pointers.
I have to make a function which concatenates two strings but I have to add a '\n' after the first word. I figured everything out and for some reason it doesn't print out anything. Any ideas? It probably has to do something with the pointers. I just can't get my head around them. Here's the code.
char *function(char *s1, char *s2){
char *newStr;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *)malloc((size+1)*sizeof(char));
while(*s1!= '\0'){
*newStr = *s1;
newStr++;
s1++;
}
*newStr = '\n';
newStr++;
while(*s2 != '\0'){
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return newStr;
}
int main (int argc, const char * argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s",function(str1, str2));
return 0;
}
So as a result I should get:
Hello
World
but I'm not getting anything back.
You are returning a pointer to the end of the buffer rather than a pointer to the start of the buffer. Look at the last two lines of the function:
*newStr = '\0';
return newStr;
Clearly this returns a pointer to the null char, i.e. the empty string.
Solve the problem by introducing a temporary pointer which you will use to step through the output buffer. Then you can return the pointer to the beginning of the output buffer.
char *function(char *s1, char *s2){
int size = strlen(s1) + strlen(s2) + 2;//one for '\n', one for '\0'
char *result = malloc(size);
char *p = result;
while(*s1 != '\0'){
*p = *s1;
p++;
s1++;
}
*p = '\n';
p++;
while(*s2 != '\0'){
*p = *s2;
p++;
s2++;
}
*p = '\0';
return result;
}
You also need to allocate an extra char for the \n, as shown above. Finally, your calling code never frees the memory allocated by function.
I would take a look at two things:
how much space you're allocating for the new string, and compare that with how many characters you're actually writing to that string.
where in the string your returned pointer is pointing to.
You return from function() a pointer to the last element in the allocated char[] – instead of returning the pointer to the first element.
Every time you do newStr++; you increase the actual pointer you later return. to solve it you can do one of these:
create a copy of the pointer newStr, which is initialized to be the same as newStr and increase it - leave newStr as it is.
create an index [let it be i] and increase it, and use newStr[i] to access the allocated array.
I have debugged the code for you. Here is the debugged code:
char *function(char *s1, char *s2) {
char *newStr, *str;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *) malloc((size + 2) * sizeof(char));
str = newStr;
while (*s1 != '\0') {
*(newStr++) = *(s1++);
}
*newStr = '\n';
newStr++;
while (*s2 != '\0') {
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return str;
}
int main(int argc, const char *argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s", function(str1, str2));
return 0;
}
The actual problem was that as you incremented newStr until the last, when you returned it from function() it was pointing to the end of the buffer. ie '\0'. That is why it didn't show up. Now In the above code I have introduced a variable str that points at the beginning of the string newStr.
Hope you understood..
Peace...