New string functions

This is a discussion on New string functions within the C Programming forums, part of the General Programming Boards category; I took the liberty of creating some new string functions for C. The goal with these was: - Safety. No ...

  1. #1
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029

    New string functions

    I took the liberty of creating some new string functions for C.
    The goal with these was:
    - Safety. No buffer overflows.
    - If there's not enough room in the buffer to complete the operation, return the space needed.
    - The ability to use C++-like strings. It supports dynamically allocated strings that will handle memory management to make sure there's enough room for operations.
    - Performance. Instead of using the old C-style way of using null-terminators for getting length, it keeps track of the length itself, leading to speedups (albeit slightly more memory use).
    - Slight C++-compatibility (such as constructors, destructors and an iostream overload). Nothing more.

    So here is the code:
    Snip: Deleted; new code below.

    And now for criticism, please.
    The functions can handle non-dynamic strings, in which case it will fail if no space is available. The 3rd parameter allows the caller to acquire the needed space for the operation to complete.
    The strstr and strchr functions returns the position from the beginning of the string that the match was found. This is because returning a char* pointer to a dynamic string could lead to disastrous results. Therefore, to protect against mistakes, the position is returned and a char* pointer could be acquired from the original string, if required.
    Last edited by Elysia; 03-28-2009 at 05:46 AM. Reason: Saving space for new code
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #2
    Registered User
    Join Date
    Feb 2009
    Posts
    138
    i can't count the times i've tried to come up with a generic string library for c that's better than doing things manually. more power to you if you can pull it off, but if you're going to write a library for c, it should compile as c. yours doesn't.

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    That's just weird. I DID try to compile it, yet now it gives me compile errors?
    I will fix them.
    Besides, this is just a little to spend time on for fun.

    UPDATE:
    Alright, power to you. Now it compiles fine under C90.
    I wonder if there's a macro to see if it compiles under C90 or C99?
    Last edited by Elysia; 03-27-2009 at 08:55 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Registered User
    Join Date
    Dec 2008
    Location
    Black River
    Posts
    128
    - I think your CopyStrInt is way too complicated. Using an internal function to append and copy is fine, but the signature takes too many parameters. It shouldn't require more than a SStr*, a const SStr*, and perhaps another auxiliary parameter, while modyfing the mutable SStr.

    - By using strcpy, strchr, strstr, etc, you are explicitly negating the possibility of using embedded \0's in the string. Furthermore, since you have the length of the strings, the functions memcpy, memmove and memchr are faster and let you use nil characters.

    - You are forgetting to check for NULL in essentially every function. strlen, for example, will most likely crash if you pass it a null pointer.

    - IsEqual should negate the return value of strcmp, since strcmp returns zero on equal strings. You should use memcmp, anyway.

    There are many C libraries for strings out there. My personal favourite is bstring, but I've seen others use Glib. I recommend taking a look at the already existing ones before making one yourself.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    Quote Originally Posted by Ronix View Post
    - I think your CopyStrInt is way too complicated. Using an internal function to append and copy is fine, but the signature takes too many parameters. It shouldn't require more than a SStr*, a const SStr*, and perhaps another auxiliary parameter, while modyfing the mutable SStr.
    Well, the idea is that it will return the required space for the buffer to complete the operation if the string isn't dynamic and there's not enough space.
    Since C doesn't support default arguments (at least C90 AFAIK), there's no way to exclude it.
    But if you have an idea...

    - By using strcpy, strchr, strstr, etc, you are explicitly negating the possibility of using embedded \0's in the string. Furthermore, since you have the length of the strings, the functions memcpy, memmove and memchr are faster and let you use nil characters.
    I figured that one out. Why am I using strcpy which will use strlen to find the length?
    I actually changed to memcpy.
    But embedded \0... well, that might take a little more work. But it should be entirely doable.

    - You are forgetting to check for NULL in essentially every function. strlen, for example, will most likely crash if you pass it a null pointer.
    That is good criticism. I wonder why the code analyzer doesn't detect that?

    - IsEqual should negate the return value of strcmp, since strcmp returns zero on equal strings. You should use memcmp, anyway.
    Removed IsEqual and made CmpStr instead... I don't see the point of IsEqual really, since it should wrap the C-functions.

    There are many C libraries for strings out there. My personal favourite is bstring, but I've seen others use Glib. I recommend taking a look at the already existing ones before making one yourself.
    While that's very nice and all, this is just a small side project that I do for fun.
    Not really intending to compete with the "big" players out there.

    As my current code, I have actually transformed the C code into C++ code and packed it into a library, exposing a C interface.
    This has numerous advantages since C++ offers a lot more functionality to use and abuse, yet providing a C interface so the code can be designed--and work--with C.
    I should probably post that code in the C++ forum...
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,762
    It's utility as SStr is short lived I think. You'll be converting to a normal C string a lot and the way you do that is performance intensive, and sloppy.

    It's very frustrating to actually use unless you convert to C strings almost immediately.
    Code:
    #include <SStr.h>
    /**
    unsigned int SearchStr(const SStr* lhs, const SStr* rhs)
    {
    	return strstr(lhs->Str, rhs->Str) - lhs->Str;
    }
    
    unsigned int SearchChr(const SStr* lhs, const char c)
    {
    	return strchr(lhs->Str, c) - lhs->Str;
    }
    **/
    
    #include <stdio.h>
    int main()
    {
        char elem;
        char * haystack;
        char * needle;
        int len = 1000;
        haystack = NewDStr(EmptyStr(len)); /* exactly what it says on the tin */
        needle = NewDStr(EmptyStr(len));
    
        printf("Enter the haystack: "); fgets(haystack, len, stdin);
        printf("Enter the needle: "); fgets(needle, len, stdin);
        printf("Enter a character: "); elem = getchar();
    
        SearchChr(haytack, elem); /* how do I convert back? */
        SearchStr(haystack, needle);
        
        free(haystack); 
        free(needle);
        return 0;
    }
    Plus there is a problem in that code. Pointer arithmetic on NULL should be undefined: I'm surprised you apparently didn't look at the manual to understand exactly what string.h already does.

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    Quote Originally Posted by whiteflags View Post
    It's utility as SStr is short lived I think. You'll be converting to a normal C string a lot and the way you do that is performance intensive, and sloppy.

    It's very frustrating to actually use unless you convert to C strings almost immediately.
    Creating them might be troublesome, but C doesn't support exceptions, so I don't know how else to do it. Should it return the created string and have an extra argument for error return?

    Plus there is a problem in that code. Pointer arithmetic on NULL should be undefined: I'm surprised you apparently didn't look at the manual to understand exactly what string.h already does.
    The code lacks checking for NULL pointers, true, but I've fixed that in my current code.

    The strstr and strchr functions can--and probably will be--changed to more efficient implementations later. It would mean designing new code for finding strings without relying on strlen.
    Aside from that, I don't see where the biggest problems lie - you fail to mention.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    7,762
    > Creating them might be troublesome, but C doesn't support exceptions, so I don't know how
    > else to do it. Should it return the created string and have an extra argument for error return?

    I've been misunderstood. It's very hard to use your library with anything standard because you don't maintain terminating zeros. The thing that does return a normal C string, NewDStr, is poorly named and really performance intensive.

    I should be able to use some function that returns the buffer because I need to read it, and foo->Str elsewhere I guess. I still would be concerned about copies of the same variable (specifically the ones that are a result of struct assignment, which is a shallow copy).

    Of course, another option is just to make your library do more, but you wanted opinions now. Before you so much as used a test harness...

    > The code lacks checking for NULL pointers, true, but I've fixed that in my current code.

    Stop farting around and actually read the manual one of these days! The strstr and strchr functions return NULL if the needle is not in the haystack, and you do pointer arithmetic to compute your search results. Plus they also require zero terminated strings.
    Last edited by whiteflags; 03-27-2009 at 05:15 PM.

  9. #9
    Woof, woof! zacs7's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    3,459
    Why not use size_t instead of unsigned int? :\

    At least for one it matches the standard functions.

    Code:
    #ifndef __cplusplus
    	typedef char bool;
    	#ifndef false
    		#define false 0
    	#endif
    	#ifndef true
    		#define true 1
    	#endif
    #endif
    You might run into problems with C99 as bool is a standard type (see stdbool.h). Why not just check if bool is defined? :\
    Last edited by zacs7; 03-27-2009 at 06:10 PM.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    Quote Originally Posted by whiteflags View Post
    > Creating them might be troublesome, but C doesn't support exceptions, so I don't know how
    > else to do it. Should it return the created string and have an extra argument for error return?

    I've been misunderstood. It's very hard to use your library with anything standard because you don't maintain terminating zeros. The thing that does return a normal C string, NewDStr, is poorly named and really performance intensive.
    Oh no, you misunderstand. It does maintain null-terminating zeroes. It just doesn't use strlen to get the length.
    NewDString / NewStr returns a new SStr from a C-style string.

    I should be able to use some function that returns the buffer because I need to read it, and foo->Str elsewhere I guess.
    I am uncertain what you mean here...

    I still would be concerned about copies of the same variable (specifically the ones that are a result of struct assignment, which is a shallow copy).
    I suspect that playing around with pointers, like C-strings, might help with that.
    I took another approach--I abstracted the data type much like Windows API or any other API, hiding the true type and making NewXStr return a pointer to an "unknown type" instead, which you can make copies of pass around.

    Of course, another option is just to make your library do more, but you wanted opinions now. Before you so much as used a test harness...
    Of course I made sure the code was working, but... I'm not so much a C programmer. I will probably have very little use for these.

    > The code lacks checking for NULL pointers, true, but I've fixed that in my current code.

    Stop farting around and actually read the manual one of these days! The strstr and strchr functions return NULL if the needle is not in the haystack, and you do pointer arithmetic to compute your search results. Plus they also require zero terminated strings.
    Hey now, of course I do read manuals.
    Though I think I misunderstood your first criticism.
    First, they ARE zero-terminated.
    And secondly, I have fixed that little problem now.

    Quote Originally Posted by zacs7 View Post
    Why not use size_t instead of unsigned int? :\
    At least for one it matches the standard functions.
    Very well...

    Code:
    #ifndef __cplusplus
    	typedef char bool;
    	#ifndef false
    		#define false 0
    	#endif
    	#ifndef true
    		#define true 1
    	#endif
    #endif
    You might run into problems with C99 as bool is a standard type (see stdbool.h). Why not just check if bool is defined? :\
    I did not know that bool was a define, that is why I asked if there was a macro to see if the code was compiling as C99...
    So bool is a define... I added guards for that, too.
    (Visual Studio doesn't have stdbool.h.)


    Lots of stuff to do. Lots more fun to do!
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,671
    Quote Originally Posted by Elysia View Post
    I did not know that bool was a define, that is why I asked if there was a macro to see if the code was compiling as C99...
    So bool is a define... I added guards for that, too.
    (Visual Studio doesn't have stdbool.h.)
    That's because Visual Studio is not C99.

    Problem you have is that

    1) bool is not necessarily defined in C89 - or, if it is, it is often defined by user code so may have meanings incompatible with yours.
    2) It is a keyword in C++, so cannot be #define'd
    3) It is potentially defined, by <stdbool.h> in C99.
    4) Most C++ compilers are also C89 compilers.
    5) Some C89 compilers are not C++ compilers.
    6) Some (relatively few) C++ compilers are C99 compilers.
    7) Several C99 compilers are not C++ compilers.

    Unfortunately, the treatment of bool is one of the areas of incompatibility the C99 standard introduced with C++.

    A way to unambiguously detect a C99 compilation, incidentally, is to look for the predefined macro __STDC_VERSION__. For a C99 compilation it will have the value 199901L (the value will be increased for future versions of the C standard). C89 and C++ compilers - or, more accurately, their preprocessors - will not define that macro (unless they are also C99 compilers).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Sunshine, and read this, this, and this before posting again.

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    23,029
    New C90-compatible code, which improvements and a few new functions:
    Code:
    // C String Library.cpp : Defines the exported functions for the DLL application.
    //
    
    #include "stdafx.h"
    
    #include <string.h>
    #include <stdlib.h>
    #include "CLib.h"
    //#include <new>
    #include <assert.h>
    #include <stdio.h>
    
    struct SStrInt
    {
    	char* Str;
    	size_t Length;
    	size_t Size;
    	bool Free;
    };
    #ifndef __cplusplus
    typedef struct SStrInt SStrInt;
    #endif
    
    EError g_LastError;
    int g_LastCError;
    
    EError CopyStrInt(SStrInt* pDst, char* pDstCopyStart, SStrInt* pSrc, size_t* pReqSpace);
    EError NewStrPointer(SStrInt** pStr);
    EError ResizeStr(SStrInt* pStr, size_t NewSize);
    
    EError _GetLastError()
    {
    	return g_LastError;
    }
    
    int GetLastCError()
    {
    	return g_LastCError;
    }
    
    EError NewStrPointer(SStrInt** pStr)
    {
    	if (pStr == NULL)
    		return ERR_NULL_POINTER;
    	*pStr = (SStrInt*)malloc(sizeof(SStrInt));
    	if (*pStr == NULL)
    		return ERR_NOT_ENOUGH_MEMORY;
    	return ERR_SUCCESS;
    }
    
    SStr* NewDStr(const char* Str)
    {
    	SStrInt* pStr;
    	EError err = NewStrPointer(&pStr);
    	if (Str == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return NULL;
    	}
    	err = NewStrPointer(&pStr);
    	if (err != ERROR_SUCCESS)
    	{
    		g_LastError = err;
    		return NULL;
    	}
    	pStr->Length = strlen(Str);
    	pStr->Size = (pStr->Length + 1) * 2;
    	pStr->Str = (char*)malloc(pStr->Size);
    	if (pStr->Str == NULL)
    	{
    		// Malloc failed
    		g_LastError = ERR_NOT_ENOUGH_MEMORY;
    		return NULL;
    	}
    	pStr->Free = true;
    	memcpy(pStr->Str, Str, pStr->Length + 1); // +1 for the null char
    	g_LastError = ERR_SUCCESS;
    	return (SStr*)pStr;
    }
    
    SStr* NewStr(char* Str, size_t BufferSize)
    {
    	SStrInt* pStr;
    	EError err = NewStrPointer(&pStr);
    	if (Str == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return NULL;
    	}
    	err = NewStrPointer(&pStr);
    	if (err != ERROR_SUCCESS)
    	{
    		g_LastError = err;
    		return NULL;
    	}
    	pStr->Str = Str;
    	pStr->Length = strlen(Str);
    	pStr->Free = false;
    	pStr->Size = BufferSize;
    	g_LastError = ERR_SUCCESS;
    	return (SStr*)pStr;
    }
    
    EError FreeStr(SStr* pStr_)
    {
    	SStrInt* pStr;
    	if (pStr_ == NULL)
    		return ERR_NULL_POINTER;
    	pStr = (SStrInt*)pStr_;
    	if (pStr->Free)
    		free(pStr->Str);
    	memset(pStr, 0, sizeof(*pStr));
    	return ERR_SUCCESS;
    }
    
    EError CopyStrInt(SStrInt* pDst, char* pDstCopyStart, SStrInt* pSrc, size_t* pReqSpace)
    {
    	if (pDst == NULL || pDstCopyStart == NULL || pSrc == NULL)
    		return ERR_NULL_POINTER;
    	// Set position to copy new data
    	if (pDst->Length + pSrc->Length + 1 > pDst->Size)
    	{
    		EError err;
    		
    		// Not enough room in buffer
    		if (!pDst->Free)
    		{
    			if (pReqSpace)
    				*pReqSpace = pDst->Length + pSrc->Length + 1; // - pDst->Size;
    			return ERR_BUFFER_TOO_SMALL; // Not enough room.
    		}
    
    		err = ResizeStr(pDst, (pDst->Length + pSrc->Length + 1) * 2);
    		if (err != ERR_SUCCESS)
    			return err;
    		pDstCopyStart = &pDst->Str[pDst->Length];
    	}
    
    	// Copy new data
    	memcpy(pDstCopyStart, pSrc->Str, pSrc->Length + 1); // +1 for the null char
    
    	// Set new length
    	pDst->Length += pSrc->Length;
    	return ERR_SUCCESS;
    }
    
    size_t CopyStr(SStr* pDst_, const SStr* pSrc_)
    {
    	SStrInt* pDst = (SStrInt*)pDst_;
    	SStrInt* pSrc = (SStrInt*)pSrc_;
    	size_t ReqSpace = 0;
    	EError Err;
    	if (pDst_ == NULL || pSrc_ == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return 0xFFFFFFFF;
    	}
    	Err = CopyStrInt(pDst, pDst->Str, pSrc, &ReqSpace);
    	g_LastError = Err;
    	return ReqSpace;
    }
    
    size_t CatStr(SStr* pDst_, const SStr* pSrc_)
    {
    	SStrInt* pDst;
    	SStrInt* pSrc;
    	char* pDst__;
    	EError err;
    	size_t ReqSpace = 0;
    
    	if (pDst_ == NULL || pSrc_ == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return 0xFFFFFFFF;
    	}
    
    	pDst = (SStrInt*)pDst_;
    	pSrc = (SStrInt*)pSrc_;
    	pDst__ = &pDst->Str[pDst->Length];
    	err = CopyStrInt(pDst, pDst__, pSrc, &ReqSpace);
    	g_LastError = err;
    	return ReqSpace;
    }
    
    int CmpStr(const SStr* lhs_, const SStr* rhs_)
    {
    	SStrInt* lhs = (SStrInt*)lhs_;
    	SStrInt* rhs = (SStrInt*)rhs_;
    	if (lhs_ == NULL || rhs_ == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return 0xFFFFFFFF;
    	}
    	return strcmp(lhs->Str, rhs->Str);
    }
    
    int SearchStr(const SStr* lhs_, const SStr* rhs_)
    {
    	SStrInt* lhs = (SStrInt*)lhs_;
    	SStrInt* rhs = (SStrInt*)rhs_;
    	char* p;
    	if (lhs_ == NULL || rhs_ == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return -1;
    	}
    	p = strstr(lhs->Str, rhs->Str);
    	if (p == NULL)
    	{
    		g_LastError = ERR_NOT_FOUND;
    		return -1;
    	}
    	else
    		return p - lhs->Str;
    }
    
    int SearchChr(const SStr* lhs_, const char c)
    {
    	SStrInt* lhs = (SStrInt*)lhs_;
    	char* p;
    	if (lhs_ == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return -1;
    	}
    	p = strchr(lhs->Str, c);
    	if (p == NULL)
    	{
    		g_LastError = ERR_NOT_FOUND;
    		return -1;
    	}
    	else
    		return p - lhs->Str;
    }
    
    const char* GetCStr(const SStr* Str_)
    {
    	SStrInt* Str = (SStrInt*)Str_;
    	if (Str_ == NULL)
    		return NULL;
    	return Str->Str;
    }
    
    EError ReadInput(SStr* Str_)
    {
    	SStrInt* Str = (SStrInt*)Str_;
    	SStrInt TmpStr;
    	if (Str_ == NULL)
    		return ERR_NULL_POINTER;
    	ResizeStr(&TmpStr, 1024);
    	Str->Length = 0;
    
    	for(;;)
    	{
    		char* p = fgets(TmpStr.Str, TmpStr.Size, stdin);
    		if (p == NULL)
    		{
    			assert(!feof(stdin));
    			assert(ferror(stdin) != 0);
    			g_LastCError = ferror(stdin);
    			return ERR_C_FUNCTION;
    		}
    		TmpStr.Length = strlen(TmpStr.Str);
    		CatStr((SStr*)Str, (SStr*)&TmpStr);
    
    		p = strchr(Str->Str, '\n');
    		if (p)
    		{
    			*p = '\0'; // Strip newline
    			break;
    		}
    	}
    
    	return ERR_SUCCESS;
    }
    
    /* CAREFUL!
    	Reading from a file will NOT null-terminate a string, because it's no longer a string!
    	That means that NO function C string function will work with the buffer! */
    int ReadFromFile(SStr* Str_, unsigned int ElementSize, unsigned int Count, FILE* File)
    {
    	SStrInt* Str = (SStrInt*)Str_;
    	unsigned int n;
    	if (Str_ == NULL || File == NULL)
    	{
    		g_LastError = ERR_NULL_POINTER;
    		return 0;
    	}
    	if (Str->Size < ElementSize * Count)
    	{
    		EError Err;
    		if (!Str->Free)
    		{
    			g_LastError = ERR_BUFFER_TOO_SMALL;
    			return 0;
    		}
    		Err = ResizeStr(Str, ElementSize * Count * 2);
    		if (Err != ERROR_SUCCESS)
    		{
    			g_LastError = Err;
    			return 0;
    		}
    	}
    	n = fread(Str->Str, ElementSize, Count, File);
    	if (n < Count)
    	{
    		if (!feof(File))
    		{
    			g_LastError = ERR_IO;
    			g_LastCError = ferror(File);
    			return n;
    		}
    	}
    	g_LastError = ERR_SUCCESS;
    	return n;
    }
    
    EError ResizeStr(SStrInt* pStr, size_t NewSize)
    {
    	char* pOldBuffer;
    	char* pTemp;
    	size_t OldLength;
    
    	if (pStr == NULL)
    		return ERR_NULL_POINTER;
    	if (NewSize <= pStr->Length)
    		return ERR_SIZE_TOO_SMALL;
    
    	// Store old buffer
    	pOldBuffer = pStr->Str;
    	OldLength = pStr->Length;
    
    	// Allocate new size
    	pTemp = (char*)malloc(NewSize);
    	if (pTemp == NULL)
    		return ERR_NOT_ENOUGH_MEMORY;
    
    	// Assign new buffer
    	pStr->Str = pTemp;
    	pStr->Size = NewSize;
    
    	// Copy over old data
    	if (pOldBuffer)
    		memcpy(pTemp, pOldBuffer, OldLength + 1);
    	
    	// Free old buffer
    	free(pOldBuffer);
    	pOldBuffer = NULL;
    	pTemp = NULL;
    
    	return ERR_SUCCESS;
    }
    And header:
    Code:
    #ifndef CSTRLIB_171038_H
    #define CSTRLIB_171038_H
    
    #include <stddef.h>
    #include <stdio.h>
    
    #ifndef __cplusplus
    	#if __STDC_VERSION__ >= 19990L
    		#include <stdbool.h>
    	#else
    		#ifndef bool
    			typedef char bool;
    		#endif
    	#endif
    	#ifndef false
    		#define false 0
    	#endif
    	#ifndef true
    		#define true 1
    	#endif
    #endif
    
    enum EError
    {
    	ERR_SUCCESS = 0,			/* Function succeeded */
    	ERR_NOT_FOUND = -1,			/* The search string or character was not found */
    	ERR_NULL_POINTER = 1,		/* One or more arguments which must be non-NULL was NULL */
    	ERR_NOT_ENOUGH_MEMORY,		/* Unable to allocate enough required memory */
    	ERR_BUFFER_TOO_SMALL,		/* String was not dynamic and was too small for the new data */
    	ERR_C_FUNCTION,				/* A C library function failed. More information is avilable in an extra argument passed. */
    	ERR_NO_MORE_DATA,			/* There is no more data available to be read. */
    	ERR_MORE_DATA_AVAILABLE,	/* There is more data available to be read. */
    	ERR_SIZE_TOO_SMALL,			/* The specified size is too small. */
    	ERR_IO						/* An IO call went wrong. See the C function error constant for more information. */
    };
    
    #ifdef __cplusplus
    struct SStr { };
    #else
    struct SStr 
    {
    	char unused;
    };
    #endif
    
    #ifndef __cplusplus
    	typedef struct SStr SStr;
    	typedef enum EError EError;
    #endif
    
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    	SStr* NewDStr(const char* Str);
    	SStr* NewStr(char* Str, size_t BufferSize);
    	EError FreeStr(SStr* pStr);
    	const char* GetCStr(const SStr* Str);
    	EError ReadInput(SStr* Str);
    	int ReadFromFile(SStr* Str, unsigned int ElementSize, unsigned int Count, FILE* File);
    	EError _GetLastError();
    	int GetLastCError();
    	size_t CopyStr(SStr* pDst, const SStr* pSrc);
    	size_t CatStr(SStr* pDst, const SStr* pSrc);
    #ifdef __cplusplus
    }
    #endif
    
    #endif // CSTRLIB_171038_H
    Hopefully, I've taken care of a lot of criticism.
    I actually have added more than just string functions, but they do work with strings. The new improved fgets, for example, that will now read everything in the buffer, not leaving anything in there and automatically strips the newline.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. C++ ini file reader problems
    By guitarist809 in forum C++ Programming
    Replies: 7
    Last Post: 09-04-2008, 07:02 AM
  2. Replies: 8
    Last Post: 04-25-2008, 03:45 PM
  3. RicBot
    By John_ in forum C++ Programming
    Replies: 8
    Last Post: 06-13-2006, 07:52 PM
  4. Badly designed n string functions?
    By anonytmouse in forum C Programming
    Replies: 3
    Last Post: 11-01-2003, 06:16 AM
  5. Something is wrong with this menu...
    By DarkViper in forum Windows Programming
    Replies: 2
    Last Post: 12-14-2002, 11:06 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21