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; }
- 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. - 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
- For good, the argument must first be checked for
NULL
and return NULL
if we are given a NULL
argument. - 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.
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.- 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. - This is where the point [4] has come around to you.
- 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
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 Tuksizeof(*s)
will always return 1? Shouldn't she return the number of bytes that lies in s? - Vova Polischuck