String doesn't "rewind" itself when accessing via pointer - c

char *ft_between(char *str, size_t from, size_t to)
{
char *between;
between = malloc(16);
while ((from >= 0) && (from < to) && (to < ft_strlen(str)))
{
*(between++) = str[from++];
}
*between = '\0';
printf("%s\n", between); // print nothing
printf("%s\n", between - 16); // print between but never had to do this before...
return (between);// even on calling function the pointer still at end of string
}
I think it's because I changed the address of between using ++ but I usually do that and never had this behavior... is that because of malloc ???
Is there someting I missed ?
Is thear a way to "rewind" the string lol
If I do it via a counter ie. between[counter++] = str[from++]; it works but I wanted to do via pointers as it's faster... from what I've red !
In this example str is iterate with ++ until the end to add char
but when return in calling function a printf will print all str
void ft_nbr2str(char *str, size_t nbr, char *base, size_t base_len)
{
if (nbr >= base_len)
{
ft_nbr2str(str, (nbr / base_len), base, base_len);
while (*str != '\0')
str++;
*str = base[nbr % base_len];
}
else
*str = base[nbr];
}

I think it's because I changed the address of between using ++
It's because you modified the value of between via the ++ operator. That value is the address of something else. The address of between or any other object cannot be modified.
but I usually do that and never had this behavior.
The behavior you describe is absolutely normal, so either no, you don't usually do that, or yes you did have that behavior. In your code, you will observe the same effect on from. I really don't fathom why immediately after you execute *between = '\0'; you would expect printf("%s\n", between) to print a non-empty string. malloc has nothing in particular to do with it.
I speculate that in other cases you may have instead modified a copy of your pointer, which, naturally, does not modify the original pointer. Possibly you did this by passing your pointer (by value) to another function. Example:
void strcpy_range(char *dest, char *src, size_t from, size_t to) {
while ((from >=0) && (from < to) && (src[from] != '\0'))
{
*(dest++) = src[from++]; // dest is modified
}
*dest = '\0';
}
char *ft_between(char *str, size_t from, size_t to)
{
char *between = malloc(16);
strcpy_range(between, str, from, to);
printf("%s\n", between); // prints the extracted substring
return between; // returns a pointer to the extracted substring
}
If you want to rescue your original version without introducing a new function, then use a temporary variable to track the current location in the substring. For example,
char *ft_between(char *str, size_t from, size_t to)
{
char *between = malloc(16);
char *temp = between;
while ((from >=0) && (from < to) && (to < ft_strlen(str)))
{
*(temp++) = str[from++];
}
*temp = '\0';
printf("%s\n", between); // prints the extracted substring
return between; // returns the extracted substring
}
Addendum
The alternative example added to the question demonstrates exactly the form I speculated you might have used. The (non-)effect on the caller's copy of the pointer in that case is not analogous to or even related to the modification of the function parameter observed during execution of the first function presented in the question.

After you've incremented the pointer, it now points to a different region of memory. Since the pointer is of type char, summing one unit is the same as summing sizeof(char) units, which turns out to still be 1; to 'rewind' it, as you say, you'd just have to subtract 16 * sizeof(char) = 16 (notice you're dereferencing the pointer summed by 16, so it makes perfect sense to subtract 16 to get it back to its position, or subtract however many times you want so that it points to the location you expect it to)

After this statement
*between = '\0';
the pointer between points to an empty string. So this call of printf:
printf("%s\n", between); // print nothing
indeed will output nothing.
And this return statement
return (between);// even on calling function the pointer still at end of string
returns this pointer to an empty string.
Pay attention to that this condition
(from >=0)
does not make sense because objects of the unsigned type size_t can not be negative.
Also it is unclear why there is used the magic number 16
between = malloc(16);
and
printf("%s\n", between - 16); // print between but never had to do this before...
And the function should not output any message. It is the caller of the function that will decide whether to output something.
The function can be declared and defined the following way
char * ft_between( const char *str, size_t from, size_t to )
{
char *between;
size_t n = ft_strlen( str );
if ( n < to ) to = n;
if ( to <= from )
{
between = calloc( 1, sizeof( char ) );
}
else
{
between = malloc( to - from + 1 );
if ( between != NULL )
{
char *p = between;
while ( from != to ) *p++ = str[from++];
*p = '\0';
}
}
return between;
}

Related

Manipulating a string and rewriting it by the function output

For some functions for string manipulation, I try to rewrite the function output onto the original string. I came up with the general scheme of
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *char_repeater(char *str, char ch)
{
int tmp_len = strlen(str) + 1; // initial size of tmp
char *tmp = (char *)malloc(tmp_len); // initial size of tmp
// the process is normally too complicated to calculate the final length here
int j = 0;
for (int i = 0; i < strlen(str); i++)
{
tmp[j] = str[i];
j++;
if (str[i] == ch)
{
tmp[j] = str[i];
j++;
}
if (j > tmp_len)
{
tmp_len *= 2; // growth factor
tmp = realloc(tmp, tmp_len);
}
}
tmp[j] = 0;
char *output = (char *)malloc(strlen(tmp) + 1);
// output matching the final string length
strncpy(output, tmp, strlen(tmp));
output[strlen(tmp)] = 0;
free(tmp); // Is it necessary?
return output;
}
int main()
{
char *str = "This is a test";
str = char_repeater(str, 'i');
puts(str);
free(str);
return 0;
}
Although it works on simple tests, I am not sure if I am on the right track.
Is this approach safe overall?
Of course, we do not re-write the string. We simply write new data (array of the characters) at the same pointer. If output is longer than str, it will rewrite the data previously written at str, but if output is shorter, the old data remains, and we would have a memory leak. How can we free(str) within the function before outputting to its pointer?
A pair of pointers can be used to iterate through the string.
When a matching character is found, increment the length.
Allocate output as needed.
Iterate through the string again and assign the characters.
This could be done in place if str was malloced in main.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *char_repeater(char *str, char ch)
{
int tmp_len = strlen(str) + 1; // initial size of tmp
char *find = str;
while ( *find) // not at terminating zero
{
if ( *find == ch) // match
{
tmp_len++; // add one
}
++find; // advance pointer
}
char *output = NULL;
if ( NULL == ( output = malloc(tmp_len)))
{
fprintf ( stderr, "malloc peoblem\n");
exit ( 1);
}
// output matching the final string length
char *store = output; // to advance through output
find = str; // reset pointer
while ( *find) // not at terminating zero
{
*store = *find; // assign
if ( *find == ch) // match
{
++store; // advance pointer
*store = ch; // assign
}
++store; // advance pointer
++find;
}
*store = 0; // terminate
return output;
}
int main()
{
char *str = "This is a test";
str = char_repeater(str, 'i');
puts(str);
free(str);
return 0;
}
For starters the function should be declared like
char * char_repeater( const char *s, char c );
because the function does not change the passed string.
Your function is unsafe and inefficient at least because there are many dynamic memory allocations. You need to check that each dynamic memory allocation was successful. Also there are called the function strlen also too ofhen.
Also this code snippet
tmp[j] = str[i];
j++;
if (str[i] == ch)
{
tmp[j] = str[i];
j++;
}
if (j > tmp_len)
//...
can invoke undefined behavior. Imagine that the source string contains only one letter 'i'. In this case the variable tmp_len is equal to 2. So temp[0] will be equal to 'i' and temp[1] also will be equal to 'i'. In this case j equal to 2 will not be greater than tmp_len. As a result this statement
tmp[j] = 0;
will write outside the allocated memory.
And it is a bad idea to reassign the pointer str
char *str = "This is a test";
str = char_repeater(str, 'i');
As for your question whether you need to free the dynamically allocated array tmp
free(tmp); // Is it necessary?
then of course you need to free it because you allocated a new array for the result string
char *output = (char *)malloc(strlen(tmp) + 1);
And as for your another question
but if output is shorter, the old data remains, and we would have a
memory leak. How can we free(str) within the function before
outputting to its pointer?
then it does not make a sense. The function creates a new character array dynamically that you need to free and the address of the allocated array is assigned to the pointer str in main that as I already mentioned is not a good idea.
You need at first count the length of the result array that will contain duplicated characters and after that allocate memory only one time.
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * char_repeater( const char *s, char c )
{
size_t n = 0;
for ( const char *p = s; ( p = strchr( p, c ) ) != NULL; ++p )
{
++n;
}
char *result = malloc( strlen( s ) + 1 + n );
if ( result != NULL )
{
if ( n == 0 )
{
strcpy( result, s );
}
else
{
char *p = result;
do
{
*p++ = *s;
if (*s == c ) *p++ = c;
} while ( *s++ );
}
}
return result;
}
int main( void )
{
const char *s = "This is a test";
puts( s );
char *result = char_repeater( s, 'i' );
if ( result != NULL ) puts( result );
free( result );
}
The program output is
This is a test
Thiis iis a test
My kneejerk reaction is to dislike the design. But I have reasons.
First, realloc() is actually quite efficient. If you are just allocating a few extra bytes every loop, then chances are that the standard library implementation simply increases the internal bytecount value associated with your memory. Caveats are:
Interleaving memory management.Your function here doesn’t have any, but should you start calling other routines then keeping track of all that becomes an issue. Anything that calls other memory management routines can lead to the next problem:
Fragmented memory.If at any time the available block is too small for your new request, then a much more expensive operation to obtain more memory and copy everything over becomes an issue.
Algorithmic issues are:
Mixing memory management in increases the complexity of your code.
Every occurrence of c invokes a function call with potential to be expensive. You cannot control when it is expensive and when it is not.
Worst-case options (char_repeater( "aaaaaaaaaa", 'a' )) trigger worst-case potentialities.
My recommendation is to simply make two passes.
This passes several smell tests:
Algorithmic complexity is broken down into two simpler parts:
counting space required, and
allocating and copying.
Worst-case scenarios for allocation/reallocation are reduced to a single call to malloc().
Issues with very large strings are reduced:
You need at most space for 2 large strings (not 3, possibly repeated)
Page fault / cache boundary issues are similar (or the same) for both methods
Considering there are no real downsides to using a two-pass approach, I think that using a simpler algorithm is reasonable. Here’s code:
#include <stdio.h>
#include <stdlib.h>
char * char_repeater( const char * s, char c )
{
// FIRST PASS
// (1) count occurances of c in s
size_t number_of_c = 0;
const char * p = s;
while (*p) number_of_c += (*p++ == c);
// (2) get strlen s
size_t length_of_s = p - s;
// SECOND PASS
// (3) allocate space for the resulting string
char * dest = malloc( length_of_s + number_of_c + 1 );
// (4) copy s -> dest, duplicating every occurance of c
if (dest)
{
char * d = dest;
while (*s)
if ((*d++ = *s++) == c)
*d++ = c;
*d = '\0';
}
return dest;
}
int main(void)
{
char * s = char_repeater( "Hello world!", 'o' );
puts( s );
free( s );
return 0;
}
As always, know your data
Whether or not a two-pass approach actually is better than a realloc() approach depends on more factors than what is evident in a posting on the internet.
Nevertheless, I would wager that for general purpose strings that this is a better choice.
But, even if it isn’t, I would argue that a simpler algorithm, splitting tasks into trivial sub-tasks, is far easier to read and maintain. You should only start making tricky algorithms only if you have use-case profiling saying you need to spend more attention on it.
Without that, readability and maintainability trumps all other concerns.

Howcome my function to calculate the length of a string returns a negative value?

I've written a function using pointer arithmetic to calculate the length of a string but it only seems to work properly by using a hackish methodology.
I've tried using my understanding of memory addressing to make the function work as intended.
int getLength(const char *str) {
int length;
while (*str != '\0') {
length += str - (++str);
}
return abs(length);
}
int getLength(const char *str) {
int length;
while (*str != '\0') {
length += str + (++str);
}
return length;
}
The first function returns the correct length, but the second one returns 0, why is this?
Both functions are incorrect because:
you do not initialize length, so the behavior is undefined.
taking the absolute value is a lame attempt at fixing the problem... correcting the symptoms, but not addressing the problem. Don't do this, investigate the issue.
length += str - (++str); has undefined behavior because the side effect on str may happen before or after taking the value of the left operand str.
length += str + (++str); is a constraint violation: adding 2 pointers is not allowed in C.
You should instead write:
size_t getLength(const char *str) {
size_t length = 0;
while (*str != '\0') {
length++;
str++;
}
return length;
}
Depending on the target architecture, it may be more efficient to only increment str and compute the difference at the end:
size_t getLength(const char *str) {
const char *p = str;
while (*p++ != '\0')
continue;
/* p was incremented beyond the null terminator, hence decrease the difference by 1 */
return p - str - 1;
}
Your functions have a lots of issues:
You do not initialize the automatic variables.
Your pointer arithmetic does not make too much sense (at leat I cant understand what is the logic behind it)
result pf operations where on one size you have the lvalue and post(pre)increment or decrement is undefined (it saying quicker an Undefined Behaviour)
Below you have two almost the same versions of the strlen function. Sometimes small changes may have large impact on the function peformance depending on the target hardware.
this verison is more optimal for ARM targets
size_t getlen(const char *s)
{
const char *p = s;
while(*p++);
return p - s - 1;
}
this one is better for the x86 targets
size_t getlen(const char *s)
{
const char *p = s;
while(*p)
{
p++;
}
return p - s;
}

copy bytes without memcpy()

It's a home work. I want to implement memcpy(). I was told memory area must not overlap. Actually I don't understand what that means, because this code works fine, but there is a possibility of memory overlap. How to prevent it?
void *mem_copy(void *dest, const void *src, unsigned int n) {
assert((src != NULL) && (n > 0));
int i = 0;
char *newsrc = (char*)src;
char *newdest = (char*)dest;
while (i < n) {
newdest[i] = newsrc[i];
i++;
}
newdest[i]='\0';
return newdest;
}
When source and destination memory blocks overlap, and if your loop copies one element after the other starting from index 0, it works for dest < source, but not for dest > source (because you overwrite elements before having copied them) and vice versa.
Your code starts copying from index 0, so you can simply test which situations work and which not. See the following test code; It shows how moving a test string forward fails, whereas moving the string backwards works fine. Further, it shows how moving the test string forward works fine when copying from backward:
#include <stdio.h>
#include <string.h>
void *mem_copy(void *dest, const void *src, size_t n) {
size_t i = 0;
char* newsrc = (char*)src;
char* newdest = (char*)dest;
while(i < n) {
newdest[i] = newsrc[i];
i++;
}
return newdest;
}
void *mem_copy_from_backward(void *dest, const void *src, size_t n) {
size_t i;
char* newsrc = (char*)src;
char* newdest = (char*)dest;
for (i = n; i-- > 0;) {
newdest[i] = newsrc[i];
}
return newdest;
}
int main() {
const char* testcontent = "Hello world!";
char teststr[100] = "";
printf("move teststring two places forward:\n");
strcpy(teststr, testcontent);
size_t length = strlen(teststr);
printf("teststr before mem_copy: %s\n", teststr);
mem_copy(teststr+2, teststr, length+1);
printf("teststr after mem_copy: %s\n", teststr);
printf("\nmove teststring two places backward:\n");
strcpy(teststr, testcontent);
length = strlen(teststr);
printf("teststr before mem_copy: %s\n", teststr);
mem_copy(teststr, teststr+2, length+1);
printf("teststr after mem_copy: %s\n", teststr);
printf("move teststring two places forward using copy_from_backward:\n");
strcpy(teststr, testcontent);
length = strlen(teststr);
printf("teststr before mem_copy: %s\n", teststr);
mem_copy_from_backward(teststr+2, teststr, length+1);
printf("teststr after mem_copy: %s\n", teststr);
}
Output:
move teststring two places forward:
teststr before mem_copy: Hello world!
teststr after mem_copy: HeHeHeHeHeHeHeH
move teststring two places backward:
teststr before mem_copy: Hello world!
teststr after mem_copy: llo world!
move teststring two places forward using copy_from_backward:
teststr before mem_copy: Hello world!
teststr after mem_copy: HeHello world!
So one could write one function, which decides whether to start copying from index 0 or from index n depending on whether the caller wants to copy forward or backward. The tricky thing is to find out whether the caller will copy forward or backward, since a pointer arithmetic on src and dest like if (src < dest) copy_from_backward(...) is actually not permitted in every case (cf. the standard, e.g. this draft):
6.5.9 Equality operators
When two pointers are compared, the result depends on the relative
locations in the address space of the objects pointed to. If two
pointers to object or incomplete types both point to the same object,
or both point one past the last element of the same array object, they
compare equal. If the objects pointed to are members of the same
aggregate object, pointers to structure members declared later compare
greater than pointers to members declared earlier in the structure,
and pointers to array elements with larger subscript values compare
greater than pointers to elements of the same array with lower
subscript values. All pointers to members of the same union object
compare equal. If the expression P points to an element of an array
object and the expression Q points to the last element of the same
array object, the pointer expression Q+1 compares greater than P. In
all other cases, the behavior is undefined.
Though I've never been in a situation where src < dest did not give me the desired results, comparing two pointers this way is actually undefined behaviour if they do not belong to the same array.
Hence, if you ask "how to prevent it?", I think that the only correct answer must be: "It's subject to the caller, because function mem_copy cannot decide whether it may compare src and dest correctly."
Actually I don't understand what doest that mean [for memory to overlap]
Consider this example:
char data[100];
memcpy(&data[5], &data[0], 95);
From the program's point of view, the range of addresses from src to src+n must not overlap the range from dest to dest+n.
if there is possibility of memory overlap, how to prevent it?
You can make your algorithm work with or without an overlap by deciding to copy overlapping regions from the back if src has numerically lower address than dest.
Note: Since you are doing memcpy, not strcpy, forcing null termination with newdest[i]='\0' is incorrect, and needs to be removed.
There are some issues in your re-implementation of memcpy():
The size argument n should have type size_t. The index variable i should have the same type as the size argument.
It is OK to pass a count of 0. Indeed your code would behave correctly in this case, remove the test from the assert().
Avoid casting away the const qualifier unless absolutely necessary.
Do not tack a '\0' at the end of the destination, it is incorrect and will cause buffer overruns.
Here is a corrected version:
void *mem_copy(void *dest, const void *src, size_t n) {
assert(n == 0 || (src != NULL && dest != NULL));
size_t i = 0;
const char *newsrc = (const char *)src;
char *newdest = (char *)dest;
while (i < n) {
newdest[i] = newsrc[i];
i++;
}
return dest;
}
Regarding the potential overlap between the source area and the destination area, your code's behavior will be surprising if the destination pointer is greater than the source, but within the source area:
char buffer[10] = "12345";
printf("before: %s\n", buffer);
mem_copy(buffer + 1, buffer, 5);
printf("after: %s\n", buffer);
Will output:
before: 12345
after: 111111
There is no completely portable way to test for such overlap, but it is quite easy on non exotic architectures at some small cost in execution time and code size. The semantics of memcpy() is that no such test is assumed to be performed by the library, so the programmer should only call this function if there is no possibility for source and destination areas to overlap. When in doubt, use memmove() that handles overlapping areas correctly.
If you wish to add an assert for this, here is a mostly portable one:
assert(n == 0 || newdest + n <= newsrc || newdest >= newsrc + n);
Here is a simple rewrite of memmove(), albeit not completely portable:
void *mem_move(void *dest, const void *src, size_t n) {
assert(n == 0 || (src != NULL && dest != NULL));
const char *newsrc = (const char *)src;
char *newdest = (char *)dest;
if (newdest <= newsrc || newdest >= newsrc + n) {
/* Copying forward */
for (size_t i = 0; i < n; i++) {
newdest[i] = newsrc[i];
}
} else {
/* Copying backwards */
for (size_t i = n; i-- > 0;) {
newdest[i] = newsrc[i];
}
}
return dest;
}

Return for type void function

I'm trying to program a function that allows me to locate a substring "from" in a string "src", and replace the "from" substring with the "to" substring in all cases, and output the new string through "dest"; however I think my code looks a bit iffy, and I do not understand (conceptually) how I would return an output with dest, given that the output is of type void. I was wondering if someone could offer some assistance?
for example:
find_replace("pooppoop poop", "poo", "hel", dest) should return
"helphelp help"
thank you!
void find_replace(char* src, char* from, char* to, char* dest)
{
dest = (char * ) malloc(sizeof(src)+sizeof(from));
int i;
int j;
int check = 1;
for (i = 0; i <= strlen(src) - 1; i++) {
if (src[i] == from[0]) {
for (j = 0; j <= strlen(from) - 1; i++) {
if (src[i+j] != from[j]) {
check = 0;}
else {
continue;
}}}
if (check == 1) {
char * str3 = (char *) malloc(1 + strlen(&src[i]) + strlen(to));
strcpy(str3, &src[i]);
strcat(str3, to);
}
else { continue; }
}
return ;
You allocate memory for a new string in your example, but the calling code cannot acces this variable.
Basically, there are three methods to pass a string. Each has advantages and drawbacks.
Pass a fixed-size buffer
int repl1(char *dest, int n, const char *src, const char *find, const char *repl)
Here, the calling function provides a buffer to which the function can write. It is a good idea to provide a maximum buffer length, so that the function does not overflow that buffer. The arguments, whose contents you don't intend to change should be const, i.e. pointers to unmodifiable data.
Such a function can be void, but it could also return an integer that indicates how long the string in dest is.
The advantage is that you can easily pass automatic buffers. The disadvantage ist that these buffers might be too small for the task.
Call the function like this:
char buf[80];
int n = repl1(buf, sizeof(buf), str, "this", "that");
Return allocated memory
char *repl2(const char *src, const char *find, const char *repl)
Here, the function should allocate new memory to hold the buffer. The function returns the pointer to the new memory. That memory "belongs" to the calling function, which then is responsible for freeing the memory.
The advantage is that the function can allocate enough memory for the task. The disadvantage is that the calling function must take care of managing the new memory.
Call the function like this:
char *dest = repl2(str, "this", "that");
// Do stuff whith 'dest' ...
free(dest);
Pass a pointer to a poiner to char
int repl3(char **dest, const char *src, const char *find, const char *repl)
This is a variant of returning the pointer, where the pointer is passed by reference and can therefore be changed. The function also has access to the old contents to the dest char buffer. That is not useful in your case. I have only mentioned this possibility for completeness.
Call the function like this:
char *buf;
int n = repl3(&buf, str, "this", "that");
This answer addresses the ways of passing data. Your code uses the second method, so you should return dest, but not pass it in as parameter. I have not looked at your function logic.
Void type method won't return anything, what you can do is change the type of your function to string and return a string.
Void means nothing, so you can't return a value with a void function.
I assume you want to use call-by-reference instead of call-by-value, if you want to use a void function.
This means, that you give a pointer to the function, to tell where your array is located. Then you work with your 'real' array, instead of a copy.
[Apart from analyzing the logic of your function] A function with a return type void won't [and can't] return any value using the return statement. Also, worthy to mention, you cannot return more than one value [as you need] using a return statement, either.
To get the return value(s) in your case, you're supposed to call your function and pass pointer(s) to char as argument. Then, inside your function, when you assign/alter values of the locations pointed by those pointers, they will get modified and after returning from your function, in the caller function, you'll have the modified value.
This is another way to have more than one return value at a time from a called function.
printf("%s\n",find_replace("pooppoop poop", "poo", "hel", dest));
char * find_replace(char* src, char* from, char* to, char* dest)
{
dest = (char * ) malloc(sizeof(src)+sizeof(from));
int i;
int j;
int check = 1;
for (i = 0; i <= strlen(src) - 1; i++) {
if (src[i] == from[0]) {
for (j = 0; j <= strlen(from) - 1; i++) {
if (src[i+j] != from[j]) {
check = 0;}
else {
continue;
}}}
if (check == 1) {
char * str3 = (char *) malloc(1 + strlen(&src[i]) + strlen(to));
strcpy(str3, &src[i]);
strcat(str3, to);
return str3 ;
}
else { continue; }
}
return "";
}
The line:
dest = (char * ) malloc(sizeof(src)+sizeof(from));
overrides the address passed in
void find_replace(char* src, char* from, char* to, char* dest)
If you want to allocate memory inside the function (which I think you have to, because the caller cannot know how much to reserve), you have to tell the caller where the result data ends up in. Either you opt for an out-parameter:
void find_replace(char* src, char* from, char* to, char** dest)
{
*dest = malloc(...);
or, what I would prefer, you return the pointer:
char* find_replace(char* src, char* from, char* to)
{
char* dest = malloc(...);
// ...
return dest;
}

pointers strings

to copy at the correct place but doesn't stop after the count is reached. I thought my code should work as follows
char har *orig, int start, int count, char *final);
int main(void)
{
const char source[] = "one two three";
char result[] = "123456789012345678";
printf("%s\n",GetSubstring(source, 4, 3, result));
return 0;
}
char r *orig, int start, int count, char *final)
{
char *temp = (char *)orig;
final = temp;
}
for ( ; *temp && (count > 0) ; count--)
{
rn final;
}
The first for loop doesn't check if temp array exists (how would it check for existence of an allocated memory without asking memory manager in some way?!). The temp is merely a pointer. What you're checking for is that the orig string doesn't have a zero within the first start bytes. That's OK, perhaps' that's what you meant by "existence".
Your intention is to copy from orig to final, yet you reset final to orig. That's where your error is. You must remove that line and it fixes the problem.
You don't need to create the temp pointer, you can use the orig pointer. You're free to modify it -- remember, function arguments are in effects local variables. Function arguments in C are pass-by-value, you implement pass-by-reference by passing pointers (which are values!) to data.
I should add perhaps that the premise of this function is somewhat broken. It "works", but it's not what one might reasonably expect. Notably:
There's no indication that the source string was shorter than start.
There's no indication that the source string was shorter than start + count.
Perhaps those are OK, but in cases where those conditions could be an error, it should be possible for the user of the function to get an indication of it. The caller would know what's expected and what's not, so the caller can determine it if only you'd provide some feedback to the caller.
You're returning the position that's one past the end of the output -- past the zero-termination. That's not very convenient. If one were to use the returned value to concatenate a subsequent string, it'd have to be decremented by one first.
Below is the fixed code, with sanely named variables.
char *GetSub(const char *src, int start, int count, char *dst)
{
for ( ; *src && (start > 0) ; start--)
{
src++; /* Note: *src++ works too, but is pointless */
}
for ( ; *src && (count > 0) ; count--)
{
*dst++ = *src++;
}
*dst++ = 0;
return dst; /* Notice: This returns a pointer to the end of the
memory block you just wrote. Is this intentional? */
}
There are several problems in what you have written. Let's enumerate:
char *temp = (char *)orig; - You're assigning a const char * (you promise not to modify) to a char * (you break that promise). Wrong thing to be doing.
final = temp. No this does not make the original final (the copy held by the caller) change at all. It achieves nothing. It changes your (function's) copy of final to point to the same place that temp is pointing.
*temp++; - There's no point de-referencing it if you're not going to use it. Incrementing it of course, is correct [see comment thread with KubaOber below].
final++ = *temp++; - This is just confusing to read.
*final++ = 0; return final; - You're setting the value at the address final to '0'. Then you're incrementing it (to point to somewhere in space, maybe towards a black hole). Then returning that pointer. Which is also wrong.
What you really should do is to wrap strncpy in a convenient way.
But if you insist to write your own, you'd probably want your function to be something as simple as:
char *GetSub(const char *orig, int start, int count, char *final)
{
int i;
for (i = 0; i < count; i++)
{
final[i] = orig[i+start];
if (final[i] == '\0')
break;
}
final[i] = '\0';
return final; /* Yes, we just return what we got. */
}
The problem is with the following line:
final = temp;
Remove it, and the problem should be resolved.
char *a="abcdefgh";
i want string "cde" to be copied into another.
index i got is 3(your start).
char *temp=malloc(3*sizeof(char))
strncpy(temp,a+3,3);
is this what you need?
Change your GetSubfunction:
char *GetSub(const char *orig, int start, int count, char *final)
{
char *temp = (char *)orig;
// with original final = temp and final++ you loose final valid pointer
char *final2 = final;
for ( ; *temp && (start > 0) ; )
{
start--;
// you don't need to dereference temp
temp++;
}
for ( ; *temp && (count > 0) ; count--)
{
*final2++ = *temp++;
}
*final2 = 0;
// return a valid pointer
return final;
}
you have some mistakes on your code :
char *GetSub(const char *orig, int start, int count, char *final)
{
char *temp = (char *)orig;
//final = temp; /* Why this? */
for ( ; *temp && (start > 0) ; )
{
start--;
temp++; /* Instead of *temp++ */
}
for ( ; *temp && (count > 0) ; count--)
{
*final++ = *temp++;
}
*(final+count) = '\0';
return final;
}
Hope this help.

Resources