*left (Source, Size)

By Roland007

Expert (80)

Roland007의 아바타

14-03-2018, 15:40

I tried to write a left function that returns the first N characters of a given string.

This code works but does not work like I want it to:

#include 
#include 

VOID left (target,source,size) 
char *target;
char *source;
int size;
{
	if (strlen(source) > size) {
		strncpy(target,source,size);
	}
	else {
		target= source;
	}
}

VOID main () {
	char *doel;
	char *ts="Checkers\0";
	left(doel,ts,5);
	printf("%s\n",doel);
}

Rewriting the code like this, brings hell down, because everything breaks. The system might hang, the system might print more characters than requested etc. This usually indicates pointer problems, but how do I solve them?

// this is hell
#include 
#include 

char *left (source,size) 
char *source;
int size;
{
	char *target=0; // needs to be initialized or will spit out help information about command2.com
	if (strlen(source) > size) {
		strncpy(target,source,size);
		return target;
	}
	else {
		return source;
	}
}

VOID main () {
	char *ts="Checkers\0";
	printf("%s\n",left(ts,5);
}

I tried to initialize target by allocating exactly the right number of bytes with malloc() and putting zero at every address through a for loop but no-way. Does anyone have a clean way to return a substring in C like char *substr = left(source,4)?

Thanks

Login or 등록 to post comments

By Grauw

Ascended (8206)

Grauw의 아바타

14-03-2018, 16:24

In the first snippet, the target pointer is uninitialised so you are writing your output string to a random place in memory. You need to point it to an allocated buffer (on either the stack or the heap) big enough to fit the left part of the string. That it does not crash the program is pure coincidence, because it can very easily overwrite program code, system code or data.

In the second snippet, you initialise your pointer to 0 rather than allocated memory, so the strncpy() call will overwrite the DOS entry points which reside in that region of memory, pretty much a guaranteed crash.

You should stick to the pattern of the first snippet, where you pass in a target buffer (one allocated in the caller’s scope), since any buffer allocated locally within left() will go out of scope when you return, and the pointer will point to uninitialised memory on the stack, which will be overwritten in the call to printf.

By Timmy

Expert (91)

Timmy의 아바타

14-03-2018, 17:44

Also, I don't know about MSX-C, but in most C versions, strncpy copies exactly size characters from the source to the destination, if the size is smaller than the string at the source.

That means that your destination array(!) does not end with a null character in these cases. If you print it, it will continue to print everything until the program finds a '\0' somewhere. Therefore, in these cases, you need to append a null character to your result before it is being treated like a proper string.

By Roland007

Expert (80)

Roland007의 아바타

14-03-2018, 18:05

@all, thanks. In the second snippet I had also tried to assign a memory block with malloc (size) and wiped that area before using it. Results were also unpredictable. I also have a line target [ size ]= "\0" in my code that will prevent printf from printing until it accidentally hits a zero.

Downside of this approach that you can't nest functions. Stupid question: these routines exist in the basic rom. From a performance perspective (speed/size), would using a call to the rom be efficient?