Hey. I am writing a function that should take a string as a parameter and allocate a separate memory location for this string using malloc (). Maybe I didn’t figure it out, but it should be a function like strdup (). Please tell me what I'm doing wrong. In the code, I create a pointer to char and allocate memory, but when I check how many bytes I allocated malloc () to the pointer, I get 1. As a result, when I try to copy the input string to s, I get an empty string. Well, at least in the terminal, I get nothing from this line.

Here is the program code:

#include <stdlib.h> char* strdub(char* str){ int size = 0; while(*str){ size++; str++; } printf("size: %d\n", size); //размер входной строки char* s = (char*)malloc(sizeof(*str) * size); printf("size of char: %d\n", sizeof(*s)); //проверяю, сколько символов получил while(*str){ *s = *str; s++; str++; } return s; } 

I do a check on this:

 #include <stdlib.h> #include <stdio.h> #include "header.h" int main(){ char* hello = "hello world"; char* get_hello = strdub(hello); printf("%s\n", get_hello); return 0; } 

And that's what I get Result

  • Break the function into smaller ones. - Abyx
  • one
    To the second while str already ran away. - avp
  • one
    @VovaPolischuck does not seem to even understand what you are doing. sizeof(*s) (for the data types in the example above) will return 1 always and on all platforms with which you come across (although ... there are those where this is not the case). In addition, you inject str ... and who, when copied, will restore it to its original state? Therefore, @abyx proposed to break into small functions: strlen, strcpy (or rather analogs) - Monah Tuk
  • @Monah Tuk, you're right. I really just started to learn C and therefore I have some (in your opinion) stupid questions. But nevertheless, could you explain why sizeof(*s) will always return 1? Shouldn't she return the number of bytes that lies in s? - Vova Polischuck
  • one
    @VovaPolischuck, there is no standard way to find out by the pointer, what size block it points to. - dzhioev

1 answer 1

I will make a general answer :)

To start with the inline by code, what problems are visible there:

 #include <stdlib.h> char* strdub(char* str){ // [1] int size = 0; // [2] while(*str){ // [3] size++; str++; // [4] } printf("size: %d\n", size); //размер входной строки char* s = (char*)malloc(sizeof(*str) * size); // [5] // [6] printf("size of char: %d\n", sizeof(*s)); //проверяю, сколько символов получил while(*str){ // [7] *s = *str; s++; // [8] str++; } return s; } 
  1. Immediately learn to observe const correctness . In this case, your string str does not modify the data stored in it, so the function argument should be defined as: const char* str , which tells us that we are dealing with immutable data and guarantee the user that this data will not be changed during the call. At a minimum, this is an element of self-documenting code and the ability to avoid some annoying errors.
  2. Try not to use for sizes that can only be positive sign values. In stdlib.h there is a declaration of the required type: size_t
  3. For good, the argument must first be checked for NULL and return NULL if we are given a NULL argument.
  4. You work with the original pointer, so you lose its original value. In some cases, this is justified, right there you need it further down the code.
  5. malloc can return NULL and it needs to be checked. Most likely this will not happen in such primitive applications. But the practice is worth developing. It is worth noting that in C ++ it is not necessary to check the allocation of memory with new : according to the standard, it will either return non-null or throw an exception. Important : you need to allocate 1 byte more, because you need to store the sign of the end of the line - a symbol with the code 0x00.
  6. This statement has already been discussed: you dereference the pointer and ask to say the size of the zero element, respectively, you get - 1. According to the standard sizeof(char) there will always be 1. There is no standard way to find out the size of a memory block by its pointer.
  7. This is where the point [4] has come around to you.
  8. And here you repeat the error of [4], but for the return value: not only will you return a pointer to the end. So also free up memory later you can not.

According to the above, the corrected code will (well, or maybe) look like this:

 #include <stdlib.h> char* strdub(const char* str) { size_t size = 0; size_t i; if (!str) return NULL; while(str[size]) { size++; } printf("size: %u\n", size); //размер входной строки char* s = (char*)malloc(sizeof(*str) * (size + 1)); if (s == NULL) return NULL; for (i = 0; i < size; ++i) s[i] = str[i]; s[size] = '\0'; return s; } 

Here is the code to check: http://cpp.sh/2k4rv

And this is how it can be reorganized into separate challenges, which, then, can be completely reused:

 #include <stdlib.h> size_t str_len(const char *str) { size_t size = 0; if (!str) return 0; while (*str++) ++size; return size; } void str_cpy(char *dst, const char *src, size_t len) { dst[len] = '\0'; while (len --> 0) *dst++ = *src++; } char* strdub(const char* str) { size_t size = str_len(str); if (!size) return NULL; printf("size: %u\n", size); //размер входной строки char* s = (char*)malloc(sizeof(*str) * (size + 1)); if (s == NULL) return NULL; str_cpy(s, str, size); return s; } 

And for verification: http://cpp.sh/55w4

  • Funny to p.2 - recently read "The Go programming language" by Kernigan and Donovan - so, they prove that despite the fact that any indices can take only non-negative values, you should still use the int type for them. But Kernighan is C :) By the way, there is a certain reason: in C ++, there is an exception mechanism for errors, and in C or Go, how to show an incorrect index? ... - Harry
  • Well, if you understand what ptr[i] interpreted into, then it’s possible to sign :) for example, such code is quite legitimate: ideone.com/rR8YT5 . With errors, you need to do so that either the user processes it or falls. Therefore, I am in favor of storing an error, using a modified parameter of a function, an error has occurred - writing a code or a sign. If the parameter is null, call abort() . - Monah Tuk