how to create a substring without using malloc() - c

How can I implement a substring function such as the following that returns the substring but without using malloc() in the process so I don't have to worry about freeing the associated memory elsewhere in my code using the free() function. Is this even possible?
const char *substring(const char *string, int position, int length)
{
char *pointer;
int c;
pointer = malloc(length+1);
if (pointer == NULL)
{
printf("Unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
for (c = 0 ; c < position -1 ; c++)
string++;
for (c = 0 ; c < length ; c++)
{
*(pointer+c) = *string;
string++;
}
*(pointer+c) = '\0';
return substr;
}
UPDATE: 30 DEC 2012
Having considered all the answers and comments it's clear that essentially what I'm trying to do is create a dynamically sized array (i.e. the substring) and that is not possible in C without somewhere along the way having to use some kind of malloc() function and a subsequent free() call on the substring pointer or without the aid of a garbage collector. I attempted to integrate the libgc garbage collector as kindly suggested by #elhadi but so far have not been able to get this to work in my Xcode project. So I have opted to stick with using the following code with malloc() and free().
char * subStr(const char* srcString, const int offset, const int len)
{
char * sub = (char*)malloc(len+1);
memcpy(sub, srcString + offset, len);
sub[len] = 0;
return sub;
}
int main()
{
const char * message = "hello universe";
char * sub = subStr( message, 6, 8 );
printf( "substring: [%s]", sub );
free(sub);
}

I see two options:
If you can destroy the source string (usually a bad thing):
{
string[ position + length] = 0;
return & string[ position ];
}
Note: (see Cole Johnsons note: free no longer works on the returned pointer!)
If you can't modify the source string:
Modify your methods signature so that the caller has to worry about it:
const char *substring(const char *source, char* destination, int position, int length)
And put the modified string into destination (and return it).
And do not even think about this:
const char *substring(const char *string, int position, int length)
{
char *pointer;
int c;
static char modifiedString[256];
...
return modifiedString;
}
Using a static variable inside the function for the modified results...
(This is not thread-safe (not re-entrant!) )

Use a local buffer (an auto array) and a function like this:
void substr(char *dst, const char *src, size_t loc, size_t len)
{
memcpy(dst, src + loc, len);
dst[len] = 0;
}
Call it like this:
const size_t size = 3;
char buf[size + 1]; // this is an auto array, it will be "freed" at the end of the scope
substr(buf, "abcdFOObar", 4, size);
Always ensure the buffer is at least len + 1 bytes long to avoid buffer overflow errors.

const char *substring(const char *string, char *substr, int position, int length)
{
int c;
for (c = 0 ; c < position -1 ; c++)
string++;
for (c = 0 ; c < length ; c++)
{
*(substr+c) = *string;
string++;
}
*(substr+c) = '\0';
return substr;
}
calling function...
int main(int argc, char * argv[]) {
char substr[10];
substring("hello! World", &substr[0], 2, 4);
}

The best way to do it is:
typedef struct vstr_t {
char *s;
int len;
} vstr_t;
#define vstr_set(d, l) \
({ \
vstr_t vs = {.s = d, .len = l}; \
\
vs; \
})
#define vstr_fmt_arg(vs) (vs).len, (vs).s
int main()
{
const char *message = "hello universe";
printf( "substring: [%.*s]\n", vstr_fmt_arg(vstr_set(smpl + 6, 8)));
return 0;
}

You can use a garbage collector, you allocate the memory the first time, the garbage collector will free the memory when no needed.
you should include
#include "gc.h"
in the main you should make something like
GC_INIT(); /* Optional on Linux/X86;*/
and your substr function is:
char *substr(const char* buffer, const int offset, int len)
{
char sub = (char*)GC_MALLOC(len+1);
memcpy(sub, buffer + offset, len);
sub[len] = 0;
return sub;
}
you should link with libgc.a

Related

How to copy char array in C without inner function

This is my code
char function(char *dst)
{
int i;
char *arr;
i = 0;
while(dst[i] != '\0')
{
arr[i] = dst[i];
i++;
}
dst[i] != '\0'
return(arr);
}
int main(void)
{
char a[] ="asdf"
printf("%s", function(a);
}
I want to copy *dst to empty *arr but my code didn't work.
I can't understand.
How can I copy array without inner function in C(ex_strcpy, memspy....)
Thank you
Apart from missing ; and making sure that the string being passed to the function is always a '\0' terminated one ( else the program will run into side effects strcpy causes ). and returning char* instead of char, you missed allocating memory for arr
// return char * instead of char
char* function(char *dst)
{
// Note - sizeof(dst) wont work
// Neither does sizeof(dst)/sizeof(char)
// allocate one extra for '\0'
size_t size_to_alloc = (strlen(dst) + 1) * (sizeof *arr);
char *arr = malloc( size_to_alloc );
char *p = arr;
for ( ; *dst ; p++, dst++)
*p = *dst;
*p = '\0';
return(arr);
}
If you want to dynamically copy an array, you'll need to allocate memory for the char array using malloc or other equivalent. Make sure you free the memory once you're done with it. I would suggest reading some posts on malloc and allocating memory in c.
This is probably a good place to start.
https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
#include <stdio.h>
#include <stdlib.h>
char* function(char *dst, size_t length) {
int i;
// Allocating the memory needed for the char array.
char *arr = (char*) malloc (sizeof(char) * length);
i = 0;
while(dst[i] != '\0') {
arr[i] = dst[i];
i++;
}
arr[length - 1] = '\0';
return(arr);
}
int main(void) {
char a[] ="asdf";
// Getting length of the array
size_t length = sizeof(a) / sizeof(a[0]);
char* val = function(a, length);
printf("%s", val);
free(val);
}
You are missing the memory allocation and basically attempting to recode strdup. See below:
char *ft_strdup(const char *src)
{
char *dst;
int len;
len = 0;
while (src[len]) // no inner function
++len;
if (!(dst = malloc(sizeof(char) * (len + 1)))) // need 1 extra char to NULL terminate.
return NULL;
dst[len] = '\0';
while (--len > -1)
dst[len] = src[len];
return dst;
}
Note that it makes sense to code your own version of strdup and include it in your program library as this function is not part of the C Standard.
If there is a possibility of copying strings without using c functions, perhaps it can be done by doing what c functions do.
it may be interesting to see what strcpy does:
https://code.woboq.org/userspace/glibc/string/strcpy.c.html
char *
STRCPY (char *dest, const char *src)
{
return memcpy (dest, src, strlen (src) + 1);
}
infact it uses memcpy: https://code.woboq.org/gcc/libgcc/memcpy.c.html
and here the magic...
void *
memcpy (void *dest, const void *src, size_t len)
{
char *d = dest;
const char *s = src;
while (len--)
*d++ = *s++;
return dest;
}
and strlen: https://code.woboq.org/userspace/glibc/string/strlen.c.html
You can use memcpy() to copy memory directly, like in Memcpy, string and terminator and https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html In C any string has to be terminated by \0 (sentinel value)
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "World";
char destination[] = "Hello ";
/* Printing destination string before memcpy */
printf("Original String: %s\n", destination);
/* Copies contents of source to destination */
memcpy (destination, source, sizeof(source));
/* Printing destination string after memcpy */
printf("Modified String: %s\n", destination);
return 0;
}
source : https://www.educative.io/edpresso/c-copying-data-using-the-memcpy-function-in-c

copy a const char* into array of char (facing a bug)

I have following method
static void setName(const char* str, char buf[16])
{
int sz = MIN(strlen(str), 16);
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = 0;
}
int main()
{
const char* string1 = "I am getting bug for this long string greater than 16 lenght);
char mbuf[16];
setName(string,mybuf)
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Please let me know what is the correct way to code above if the restriction for buf length is 16 in method static void setName(const char* str, char buf[16])
When passing an array as argument, array decays into the pointer of FIRST element of array. One must define a rule, to let the method know the number of elements.
You declare char mbuf[16], you pass it to setName(), setName() will not get char[], but will get char* instead.
So, the declaration should be
static void setName(const char* str, char* buf)
Next, char mbuf[16] can only store 15 chars, because the last char has to be 'null terminator', which is '\0'. Otherwise, the following situation will occur:
// if I use buf in my code it is leading to spurious characters since length is greater than 16 .
Perhaps this will help you understand:
char str[] = "foobar"; // = {'f','o','o','b','a','r','\0'};
So the code should be
static void setName(const char* str, char* buf)
{
int sz = MIN(strlen(str), 15); // not 16
for (int i = 0; i < sz; i++) buf[i] = str[i];
buf[sz] = '\0'; // assert that you're assigning 'null terminator'
}
Also, I would recommend you not to reinvent the wheel, why don't use strncpy instead?
char mbuf[16];
strncpy(mbuf, "12345678901234567890", 15);
The following code passes the size of the memory allocated to the buffer, to the setName function.
That way the setName function can ensure that it does not write outside the allocated memory.
Inside the function either a for loop or strncpy can be used. Both will be controlled by the size parameter sz and both will require that a null terminator character is placed after the copied characters. Again, sz will ensure that the null terminator is written within the memory allocated to the buffer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void setName(const char *str, char *buf, int sz);
int main()
{
const int a_sz = 16;
char* string = "This bit is OK!! but any more than 15 characters are dropped";
/* allocate memory for a buffer & test successful allocation*/
char *mbuf = malloc(a_sz);
if (mbuf == NULL) {
printf("Out of memory!\n");
return(1);
}
/* call function and pass size of buffer */
setName(string, mbuf, a_sz);
/* print resulting buffer contents */
printf("%s\n", mbuf); // printed: This bit is OK!
/* free the memory allocated to the buffer */
free(mbuf);
return(0);
}
static void setName(const char *str, char *buf, int sz)
{
int i;
/* size of string or max 15 */
if (strlen(str) > sz - 1) {
sz--;
} else {
sz = strlen(str);
}
/* copy a maximum of 15 characters into buffer (0 to 14) */
for (i = 0; i < sz; i++) buf[i] = str[i];
/* null terminate the string - won't be more than buf[15]) */
buf[i] = '\0';
}
Changing one value const int a_sz allows different numbers of characters to be copied. There is no 'hard coding' of the size in the function, so reducing the risk of errors if the code is modified later on.
I replaced MIN with a simple if ... else structure so that I could test the code.

How to use malloc in this situation?

I'm a bit of a newbie at C, so please bear with me...
I have a function to count char in a string called char strLength, but I have to create a function that uses this function to count the number of characters in a passed string, mallocates a new string with space for a NULL terminator, copies the string and then returns the copy.
Here's what I have:
character counter
int strLength(char* toCount)
{
int count = 0;
while(*toCount != '\0')
{
count++;
toCount++;
}
return count;
}
and here's the beginning of the sought-after function
char* strCopy(char *s)
{
int length = strLength(s);
}
Since you are struggling with malloc, here is how the next line should look:
char* strCopy(char *s)
{
int length = strLength(s);
char *res = malloc(length+1);
// Copy s into res; stop when you reach '\0'
...
return res;
}
You want strdup. However, since I suspect this is a learning exercise:
char *strCopy(const char *src)
{
size_t l = strlen(src) + 1;
char *r = malloc(l);
if (r)
memcpy(r, src, l);
return r;
}
If you are curious how to copy strings yourself, you could replace the memcpy with something like:
char *dst = r;
while (*src)
*dst++ = *src++;
*dst = 0;
However I would suggest using library functions: if not strdup, then malloc + memcpy.
You can use strdup() clib call.
You can write something like:
char* strCopy(char *s) {
int length = strLength(s);
char *rc = (char *)malloc(length + 1);
return rc? strcpy(rc, s) : NULL;
}

C reference gone after for loop

i got a problem with my C code.
int split(char* source, char*** target, char* splitChar) {
int i;
int currentLength;
int splitCharPosition;
char* currentSubstring = source;
int splitCount = charcount(source, splitChar) + 1;
*target = (char**) malloc(splitCount * sizeof(char**));
for(i=0;i<splitCount;i++) {
splitCharPosition = indexOf(currentSubstring, splitChar);
substring(currentSubstring, target[i], 0, splitCharPosition);
currentLength = strlen(currentSubstring);
substring(currentSubstring, &currentSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
}
return splitCount;
}
The problem is that if I use the Debugger, the pointer to splitChar is set to 0x0 after the first run of the for loop.
Does anybody know why it is set to 0x0?
EDIT:
int indexOf(char* source, char* template) {
int i;
int j;
int index;
for (i = 0; source[i]; i++) {
index = i;
for (j = 0; template[j]; j++) {
if (source[i + j] != template[j]) {
index = -1;
break;
}
}
if (index != -1) {
return index;
}
}
return -1;
}
EDIT2:
int charcount(char* source, const char* countChar) {
int i;
int count = 0;
for(i=0;source[i];i++) {
if(source[i] == countChar[0]) {
count++;
}
}
return count;
}
EDIT3:
char* substring(char* source, char** target, int start, int length) {
*target = (char*) malloc(length + 1);
strncpy(*target, source + start, length);
target[length] = '\0';
return *target;
}
EDIT4:
I just noticed that if I add
char* sndfpgjps = splitChar;
to my split() code it does not delete the reference. Anyone know why?
This line:-
substring(currentSubstring, &currentSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
... will cause a memory leak, as well as being incredibly inefficient. The old substring is left dangling. and never freed.
It would be much better to write
currentSubString += splitCharPosition + 1;
I don't think that's the problem, but it's a problem.
Also, as you're using C library functions like strlen(), why aren't you using strtok or better yet, strtok_r?
I have some reservations about the code, but this works cleanly under valgrind (no leaks, no abuse). I've left the sub-functions largely unchanged except that constant strings are marked constant. The code in split() has been simplified. As I noted in a comment, I suggest writing the main split() function so that you have a local char **string_list; which you allocate and fill. Then, when you're about to return, you assign *target = string_list;. This will make it easier for you to understand what's going on. Triple indirection is nasty. You can justify it here (just), but minimize the time you spend working with triple pointers. The revision adopts that strategy.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
Note that in the second example, charcount() returns 6 but there are only 4 strings. This caused a late adjustment to the source code. (You could realloc() the result so it is exactly the right size, but it probably isn't worth worrying about unless the discrepancy is really marked — say 'more than 10 entries'.) The error handling is not perfect; it doesn't access invalid memory after failure to allocate, but it doesn't stop trying to allocate, either. Nor does it report failures to allocate individual strings — it does for failure to allocate the array of pointers.
I'd probably avoid the triple pointer by creating a structure:
typedef struct StringList
{
size_t nstrings;
char **strings;
} StringList;
You can then pass a pointer to one of these into split(), and into the utility functions such as free_list() and print_list(). The free_list() function would then modify the structure so that both elements are zeroed after the data pointed at by the structure is freed.
I'd also be tempted to use a different implementation of indexOf():
int indexOf(const char *haystack, const char *needle)
{
const char *pos = strstr(haystack, needle);
if (pos != 0)
return (pos - haystack);
return -1;
}
I do not know what substring does, nor what signature it has, but in the line
substring(currentSubstring, target[i], 0, splitCharPosition);
target[i] is only defined for i==0. I believe you wanted to write
substring(currentSubstring, (*target)[i], 0, splitCharPosition);
See if your debugger also supports data breakpoints, i.e. break if some place in memory is modified. Then place one at the actual address of splitChar, and another at the address it points to. (Since you didn't specify whether the pointer is null or points to nil.) See where it breaks. It may be that it is a completely unrelated place; that would indicate a buffer overflow.
Also, you could make at least splitChar a pointer to const. You don't actually want to modify it, right? Better idea, make it a char, not a pointer, since its name suggests that there is only one character on which you split, not a string.
The first call to substring does not look correct:
substring(currentSubstring, target[i], 0, splitCharPosition);
I suspect it should be something like the following where it indexes the actual memory that was allocated:
substring(currentSubstring, &((*target)[i]), 0, splitCharPosition);
You first need to get the value that target points at (*target) and then index off of that and pass the address of that array location.

Reversing a string in C using pointers?

Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}

Resources