I'm encountering a memory leak when I exit my program (found using valgrind) from the tokenize function I've written. Outside of this function, after I assign the tokens to other variables, I call free(tokens) where appropriate, but this doesn't fix the problem. Any help would be hugely appreciated!
Code:
/**
* Splits user input into an array of tokens.
**/
char ** tokenize(const char * s, int * n)
{
/* Sets array of strings and allocates memory, sized appropriately. */
int i;
char * token;
char ** tokens = malloc((BUF_LEN + EXTRA_SPACES) *sizeof(*token));
char buf[BUF_LEN];
strncpy(buf, s, BUF_LEN);
/* Defines first token by a whitespace. */
token = strtok(buf, " ");
i = 0;
/* While loop defines all consequent tokens also with a whitespace. */
while (token)
{
tokens[i] = malloc((strlen(token)+EXTRA_SPACES) *sizeof(*token));
strncpy(tokens[i], token, strlen(token));
i++;
token = strtok(NULL, " ");
}
* n = i;
return tokens;
}
I added a function to free your array and checked it with valgrind that there is no memory leak.
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <memory.h>
size_t BUF_LEN = 32;
int EXTRA_SPACES = 16;
int length = 0;
char ** tokenize(const char * s, int * n)
{
/* Sets array of strings and allocates memory, sized appropriately. */
int i;
char * token;
char ** tokens = malloc((BUF_LEN + EXTRA_SPACES) *sizeof(*token));
char buf[BUF_LEN];
strncpy(buf, s, BUF_LEN);
/* Defines first token by a whitespace. */
token = strtok(buf, " ");
i = 0;
/* While loop defines all consequent tokens also with a whitespace. */
while (token)
{
tokens[i] = malloc((strlen(token)+EXTRA_SPACES) *sizeof(*token));
strncpy(tokens[i], token, strlen(token));
i++;
token = strtok(NULL, " ");
length++;
}
* n = i;
return tokens;
}
/* deallocates an array of arrays of char*, calling free() on each */
void free_argv(char **argv, unsigned rows) {
for (unsigned row = 0; row < rows; row++) {
free(argv[row]);
}
free(argv);
}
int main ()
{
int i = 12;
char ** ch = tokenize("abc", &i);
free_argv(ch, (unsigned) length);
}
Output
valgrind ./a.out
==28962== Memcheck, a memory error detector
==28962== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28962== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==28962== Command: ./a.out
==28962==
==28962==
==28962== HEAP SUMMARY:
==28962== in use at exit: 0 bytes in 0 blocks
==28962== total heap usage: 2 allocs, 2 frees, 67 bytes allocated
==28962==
==28962== All heap blocks were freed -- no leaks are possible
==28962==
==28962== For counts of detected and suppressed errors, rerun with: -v
==28962== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I call free(tokens) where appropriate
free(tokens); is not enough, you must call free for each allocated item:
for (i = 0; i < n; i++) {
free(tokens[i]);
}
free(tokens);
Related
For C++ - I can add each char to each index in string array:
string *x=new string[10];
x[0] += "a";
x[0] += "b";
x[0] += "c";
x[1] += "x";
x[1] += "y";
x[1] += "z";
cout << "x[0]=" << x[0] << endl; // would be "abc"
cout << "x[1]=" << x[1] << endl; // would be "xyz"
How can I do same functionality in C? I have buff2 pointer to a char array and am trying to add char value from each index of buf. I keep getting weird values when I print out buff2 value.
char buf[255];
char *buff2;
int i=0, count=0;
buff2=(char*)malloc(512*sizeof(char));
while((n = read(fd, buf, sizeof(buf[g]))) > 0){
for(i=0; i<n; i++){
if(buf[i] == '\n'){
l++;
count2++;
}
else
{
buff2[count2]+=buf[i];
}
}
There are several problems in your C code
buff is an array for nothing because you only use buff[0]
the variable l seems never defined/initialized, and you modify it for nothing
buff2[count2]+=buf[i]; always modify the same buff2[count2] until a newline because you do not increase buff2 in that case but only when reading a newline, are you sure you want that ?
you do not end buff2 with a null character, that probably explain I keep getting weird values when I print out buff2 value.
you do not have a protection in case you write out of buff2 producing an undefined behavior
string *x=new string[10];
can be in C
char ** x = calloc(10, sizeof(char *));
I use calloc to initialize with null pointers
and an equivalent of :
x[0] += "a";
can be
strCat(&x[0], "a");
with:
char * const strCat(char ** p, const char * s)
{
if (s != NULL) {
if (*p == NULL)
*p = strdup(s);
else {
size_t len = strlen(*p);
*p = realloc(*p, len + strlen(s) + 1); /* may be detect realloc returns NULL on error */
strcpy(*p + len, s);
}
}
return *p;
}
So for instance :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * const strCat(char ** p, const char * s)
{
if (s != NULL) {
if (*p == NULL)
*p = strdup(s);
else {
size_t len = strlen(*p);
*p = realloc(*p, len + strlen(s) + 1); /* may be detect realloc returns NULL on error */
strcpy(*p + len, s);
}
}
return *p;
}
int main()
{
char ** x = calloc(10, sizeof(char *));
strCat(&x[0], "a");
strCat(&x[0], "b");
strCat(&x[0], "c");
strCat(&x[1], "x");
strCat(&x[1], "y");
strCat(&x[1], "z");
printf("x[0]=%s\n", x[0]);
printf("x[1]=%s\n", x[1]);
free(x[0]);
free(x[1]);
free(x);
return 0;
}
Compilation and execution:
% gcc -Wall a.c
% ./a.out
x[0]=abc
x[1]=xyz
%
Running under valgrind:
% valgrind ./a.out
==113490== Memcheck, a memory error detector
==113490== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==113490== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==113490== Command: ./a.out
==113490==
x[0]=abc
x[1]=xyz
==113490==
==113490== HEAP SUMMARY:
==113490== in use at exit: 0 bytes in 0 blocks
==113490== total heap usage: 7 allocs, 7 frees, 98 bytes allocated
==113490==
==113490== All heap blocks were freed -- no leaks are possible
==113490==
==113490== For counts of detected and suppressed errors, rerun with: -v
==113490== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
%
Note however each time you concatenate a new string it is needed to go through the current string to know its length, this is not done by std::string whose knows the used length whatever the way for that, as this is the case in the answer of KamilCuk
How can I do same functionality in C?
First implement/invent a "string".
After that you can implement the functionality. Remember about proper error handling. I just used abort() for brevity below, in normal code destructors should be run.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct string {
char *begin;
char *end;
size_t free;
} string;
void string_init(string *t) {
t->begin = t->end = NULL;
t->free = 0;
}
void string_fini(string *t) {
free(t->begin);
}
// iadd convention from python
int string_iadd_cstr(string *t, const char *str) {
const size_t addlen = strlen(str);
if (t->free < addlen + 1) {
const size_t curlen = t->end - t->begin;
const size_t newlen = curlen + 1 + addlen;
void *tmp = realloc(t->begin, newlen);
if (tmp == NULL) {
return -1;
}
t->begin = tmp;
t->end = t->begin + curlen;
t->free = newlen - curlen;
}
memcpy(t->end, str, addlen + 1);
t->end += addlen;
t->free -= addlen;
return 0;
}
int string_print(string *t) {
return printf("%s", t->begin);
}
int main() {
// string *x=new string[10];
string *x = malloc(10 * sizeof(*x));
if (x == NULL) abort();
for (size_t i = 0; i < 10; ++i) {
string_init(&x[i]);
}
if (string_iadd_cstr(&x[0], "a")) abort();
if (string_iadd_cstr(&x[0], "b")) abort();
if (string_iadd_cstr(&x[0], "c")) abort();
if (string_iadd_cstr(&x[1], "x")) abort();
if (string_iadd_cstr(&x[1], "y")) abort();
if (string_iadd_cstr(&x[1], "z")) abort();
// cout << "x[0]=" << x[0] << endl;
printf("%s", "x[0]=");
string_print(&x[0]);
printf("\n");
fflush(stdout);
// cout << "x[1]=" << x[1] << endl;
printf("%s", "x[1]=");
string_print(&x[1]);
printf("\n");
fflush(stdout);
// run destructors
for (size_t i = 0; i < 10; ++i) {
string_fini(&x[i]);
}
free(x);
}
Here is a simple example if you do not want to use strcat. This is a minimal example to demonstrate how one could concatenate strings, things like reallocation of memory have not been implemented.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[30] = "LOREM \n IPSUM DOLOR SIT AMET\0";
char *buff2;
int i = 0, n = 30;
buff2 = (char*)malloc(512 * sizeof(char));
//set first element of buff2 to be terminating null char
buff2[0] = '\0';
for(i = 0; i < n; i++) {
if(buf[i] != '\n') {
buff2[i + 1] = '\0'; // shift terminating null char forward
buff2[i] = buf[i];
} else {
buff2[i + 1] = '\0'; // shift terminating null char forward
buff2[i] = 'n';
}
}
printf("%s\n",buff2);
return EXIT_SUCCESS;
}
It replaces newlines with an "n" character; you can change this if you want. Of course, you want to be careful only to address elements which have actually been allocated. Does not include function to read from file because we don't have the file; this is easily implemented. I suggest you look into fgetc.
I have an array that needs to be filled with values from a string looking like this:
value0;value1;value2;value3;\n
I tried using strtok() but couldn't really figure out how to properly load more than 2 elements into table.
Desirable output is something like
arrayValues[0] = value0;
arrayValues[1] = value1;
etc.
You need to use strtok() and realloc(). Both are a bit difficult to use
char input[] = "value0;value1;value2;value3\n";
char **arrayValues = NULL;
int N = 0;
char *token = strtok(input, ";");
while(token != 0)
{
N++;
arrayValues = realloc(arrayValues, N * sizeof(char *));
if(!arrayValues)
/* out of memory - very unlikely to happen */
arrayValues[N-1] = strdup(token);
token = strtok(NULL, ";");
}
/* print out to check */
for(i=0;i<N;i++)
printf("***%s***\n", arrayValues[i]);
Note that the delimiter ';' is overwritten, if you retain it as you specified you'll have to add it to the end of the strings, which is fiddly and probably not what you really want.
At its simplest form, if the string you need to separate will remain in scope during the time you are making use of the individual tokens, then there is no need to allocate. Simply declare an array of pointers with a sufficient number of pointers for the tokens you have, and as you tokenize your string, just assign the address for the beginning of each token to the pointers in your array of pointers. That way, the pointers in your array simply point to the place within the original string where each of your tokens are found. Example:
#include <stdio.h>
#include <string.h>
#define MAXS 16
int main (void) {
char str[] = "value0;value1;value2;value3;\n",
*array[MAXS] = {NULL}, /* array of pointers */
*p = str, /* pointer to str */
*delim = ";\n"; /* delimiters */
int i, n = 0; /* loop var & index - n */
p = strtok (p, delim); /* get 1st token */
while (n < MAXS && p) { /* check bounds/validate token */
array[n++] = p; /* add pointer to array */
p = strtok (NULL, delim); /* get next token */
}
for (i = 0; i < n; i++) /* output tokens */
printf ("array[%2d] : %s\n", i, array[i]);
return 0;
}
(note: strtok modifies the original string by placing nul-terminating characters (e.g. '\0') in place of the delimiters. If you need to preserve the original string, make a copy before calling strtok)
Note above, you are limited to a fixed number of pointers, so while you are separating the tokens and assigning them to pointers in your array, you need to check the number against your array bounds to prevent writing beyond the end of your array.
Example Use/Output
$ ./bin/parsestrstrtok
array[ 0] : value0
array[ 1] : value1
array[ 2] : value2
array[ 3] : value3
Taking the parsing to the next step, where your original string may not remain in scope during the time your array values are needed, you simply need to allocate storage for each token and copy each token to your newly allocated memory and assign the starting address for each new block to the pointers in your array. That way, even if you pass your array of pointers and the string to a function for parsing, the array values remain available after the function completes until you free the memory you have allocated.
You are still limited to a fixed number of pointers, but your array is now usable wherever required in your program. The additions required for this are minimal. Note, malloc and strcpy are used below and can be replaced by a single call to strdup. However, since strdup is not part of all versions of C, malloc and strcpy are used instead. (but note, strdup does make for a very convenient replacement if your compiler supports it)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 16
int main (void) {
char str[] = "value0;value1;value2;value3;\n",
*array[MAXS] = {NULL}, /* array of pointers */
*p = str, /* pointer to str */
*delim = ";\n"; /* delimiters */
int i, n = 0; /* loop var & index - n */
p = strtok (p, delim); /* get 1st token */
while (p) { /* validate token */
/* allocate/validate storage for token */
if (!(array[n] = malloc (strlen (p) + 1))) {
perror ("malloc failed");
exit (EXIT_FAILURE);
}
strcpy (array[n++], p); /* copy token to array */
p = strtok (NULL, delim); /* get next token */
}
for (i = 0; i < n; i++) { /* output tokens */
printf ("array[%2d] : %s\n", i, array[i]);
free (array[i]); /* free memory for tokens */
}
return 0;
}
(output is the same)
Finally, you can eliminate your dependency on a fixed number of pointers by dynamically allocating the pointers and reallocating the pointers on an as needed basis. You can start with the same number, and then allocate twice the current number of pointers when your current supply is exhausted. It is simply one additional level of allocation before you start parsing, and a requirement to realloc when you have used all the pointers at hand. Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXS 16
int main (void) {
char str[] = "value0;value1;value2;value3;\n",
**array = NULL, /* pointer to pointer to char */
*p = str, /* pointer to str */
*delim = ";\n"; /* delimiters */
int i, n = 0, /* loop var & index - n */
nptrs = MAXS; /* number allocated pointers */
/* allocate/validate an initial number of pointers for array */
if (!(array = malloc (nptrs * sizeof *array))) {
perror ("malloc pointers failed");
exit (EXIT_FAILURE);
}
p = strtok (p, delim); /* get 1st token */
while (p) { /* validate token */
/* allocate/validate storage for token */
if (!(array[n] = malloc (strlen (p) + 1))) {
perror ("malloc failed");
exit (EXIT_FAILURE);
}
strcpy (array[n++], p); /* copy token to array */
if (n == nptrs) { /* pointer limit reached */
/* realloc 2X number of pointers/validate */
void *tmp = realloc (array, nptrs * 2 * sizeof *array);
if (!tmp) {
perror ("realloc - pointers");
goto memfull; /* don't exit, array has original values */
}
array = tmp; /* assign new block to array */
nptrs *= 2; /* update no. allocated pointers */
}
p = strtok (NULL, delim); /* get next token */
}
memfull:;
for (i = 0; i < n; i++) { /* output tokens */
printf ("array[%2d] : %s\n", i, array[i]);
free (array[i]); /* free memory for tokens */
}
free (array); /* free memory for pointers */
return 0;
}
note: you should validate your memory use with a memory use and error checking program like valgrind on Linux. There are similar tools for every platform. Just run your code though the checker and validate there are no memory error and that all memory you have allocated has been properly freed.
Example:
$ valgrind ./bin/parsestrstrtokdbl
==15256== Memcheck, a memory error detector
==15256== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15256== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==15256== Command: ./bin/parsestrstrtokdbl
==15256==
array[ 0] : value0
array[ 1] : value1
array[ 2] : value2
array[ 3] : value3
==15256==
==15256== HEAP SUMMARY:
==15256== in use at exit: 0 bytes in 0 blocks
==15256== total heap usage: 5 allocs, 5 frees, 156 bytes allocated
==15256==
==15256== All heap blocks were freed -- no leaks are possible
==15256==
==15256== For counts of detected and suppressed errors, rerun with: -v
==15256== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
**note above you see 5 allocations (1 for the pointers and 1 for each token). All memory has been freed and there are no memory errors.
There are probably a dozen more approaches you can take to inch-worm down your string picking out tokens, but this is the general progression of how to expand on the approach using strtok. Let me know if you have any further questions.
You can just use good old strchr function to hunt for the substring ';' terminator and malloc and realloc for memory allocations.
Make note that input str is modified (reused). In that string ';' are replaced by '\0'.
(If you need str untouched than allocate another buffer, copy the str to it and point p1,p2 pointers to it.)
The arrayValues holds pointers to the substrings:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main ()
{
char **arrayValues = malloc(sizeof(char *)); // allocate memory for string pointers
char str[] = "value1;value2;value3\n"; // input
char *p1 = str; // init pointer helpers
char *p2 = str;
int n = 0; // substring counter
// OPTIONAL if you want to get rid of ending '\n'
//--s
size_t len = strlen(str);
if(len>0)
if(str[len-1] == '\n')
str[len-1] = 0;
//--ee
while(p1 != NULL)
{
p1 = strchr(p1,';'); // find ';'
if(p1 != NULL)
{
arrayValues[n] = p2; // begining of the substring
*p1 = 0; // terminate the substring string; get rid of ';'
n++; // count the substrings
arrayValues = realloc( arrayValues, (n+1) * sizeof(char *)); // allocate more memory for next pointer
p2 = p1+1; // move the ponter after the ';'
p1 = p1+1; // we start the search for next ';'
}
else
{
arrayValues[n] = p2; // this is the last (or first) substring
n++;
}
} // while
// Output:
for (int j=0; j<n; j++)
{
printf("%s \n", arrayValues[j]);
}
printf("------");
free(arrayValues);
return 0;
}
Output:
value1
value2
value3
------
I have the following function to split a string. Most of the time it works fine, but sometimes it randomly causes a segmentation fault.
char** splitString(char* string, char* delim){
int count = 0;
char** split = NULL;
char* temp = strtok(string, delim);
while(temp){
split = realloc(split, sizeof(char*) * ++count);
split[count - 1] = temp;
temp = strtok(NULL, " ");
}
int i = 0;
while(split[i]){
printf("%s\n", split[i]);
i++;
}
split[count - 1][strlen(split[count - 1]) - 1] = '\0';
return split;
}
You have a number of subtle issues, not the least of which your function will segfault if you pass a string literal. You need to make a copy of the string you will be splitting as strtok modifies the string. If you pass a string literal (stored in read-only memory), your compiler has no way of warning unless you have declared string as const char *string;
To avoid these problems, simply make a copy of the string you will tokeninze. That way, regardless how the string you pass to the function was declared, you avoid the problem altogether.
You should also pass a pointer to size_t as a parameter to your function in order to make the number of token available back in the calling function. That way you do not have to leave a sentinel NULL as the final pointer in the pointer to pointer to char you return. Just pass a pointer and update it to reflect the number of tokens parsed in your function.
Putting those pieces together, and cleaning things up a bit, you could use the following to do what you are attempting to do:
char **splitstr (const char *str, char *delim, size_t *n)
{
char *cpy = strdup (str), *p = cpy; /* copy of str & pointer */
char **split = NULL; /* pointer to pointer to char */
*n = 0; /* zero 'n' */
for (p = strtok (p, delim); p; p = strtok (NULL, delim)) {
void *tmp = realloc (split, sizeof *split * (*n + 1));
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "splitstr() error: memory exhausted.\n");
break;
}
split = tmp; /* assign tmp to split */
split[(*n)++] = strdup (p); /* allocate/copy to split[n] */
}
free (cpy); /* free cpy */
return split; /* return split */
}
Adding a short example program, you could do the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **splitstr (const char *str, char *delim, size_t *n)
{
char *cpy = strdup (str), *p = cpy; /* copy of str & pointer */
char **split = NULL; /* pointer to pointer to char */
*n = 0; /* zero 'n' */
for (p = strtok (p, delim); p; p = strtok (NULL, delim)) {
void *tmp = realloc (split, sizeof *split * (*n + 1));
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "splitstr() error: memory exhausted.\n");
break;
}
split = tmp; /* assign tmp to split */
split[(*n)++] = strdup (p); /* allocate/copy to split[n] */
}
free (cpy); /* free cpy */
return split; /* return split */
}
int main (void) {
size_t n = 0; /* number of strings */
char *s = "My dog has fleas.", /* string to split */
*delim = " .\n", /* delims */
**strings = splitstr (s, delim, &n); /* split s */
for (size_t i = 0; i < n; i++) { /* output results */
printf ("strings[%zu] : %s\n", i, strings[i]);
free (strings[i]); /* free string */
}
free (strings); /* free pointers */
return 0;
}
Example Use/Output
$ ./bin/splitstrtok
strings[0] : My
strings[1] : dog
strings[2] : has
strings[3] : fleas
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to write beyond/outside the bounds of your allocated block of memory, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/splitstrtok
==14471== Memcheck, a memory error detector
==14471== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==14471== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==14471== Command: ./bin/splitstrtok
==14471==
strings[0] : My
strings[1] : dog
strings[2] : has
strings[3] : fleas
==14471==
==14471== HEAP SUMMARY:
==14471== in use at exit: 0 bytes in 0 blocks
==14471== total heap usage: 9 allocs, 9 frees, 115 bytes allocated
==14471==
==14471== All heap blocks were freed -- no leaks are possible
==14471==
==14471== For counts of detected and suppressed errors, rerun with: -v
==14471== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
split[count - 1][strlen(split[count - 1]) - 1] = '\0';
should look like
split[count - 1] = NULL;
You don't have anything allocated there so that you can access it and put '\0'.
After that put that line before while(split[i]) so that the while can stop when it reaches NULL.
The function strtok is not reentrant, use strtok_r() function this is a reentrant version strtok().
i have an array with n words .. i want to attach the strings togther ..
for example if the array have the following strings: "hello" "world" "stack77"
i want the function to return :"helloworldstach7 " any help how i can do something like this without Recursion and with one loop and i can only use from the string library the two functions strcpy and strlen !!
any ideas ! thanks
I NEED TO USE ONE LOOP ONLY !
char *connect(char**words,int n){
int i=0;
while(words){
strcpy(words+i,
i saw many many solutions but they all use other string functions , where i only want to use strcpy and strlen .
If to use only the two mentioned standard string functions then the function can look as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * connect( char **words, size_t n )
{
size_t length = 0;
for ( size_t i = 0; i < n; i++ ) length += strlen( words[i] );
char *s = malloc( length + 1 );
size_t pos = 0;
for ( size_t i = 0; i < n; i++ )
{
strcpy( s + pos, words[i] );
pos += strlen( words[i] );
}
s[pos] = '\0';
return s;
}
int main( void )
{
char * s[] = { "Hello", " ", "World" };
char *p = connect( s, sizeof( s ) / sizeof( *s ) );
puts( p );
free( p );
}
The program output is
Hello World
If to use only one loop then the function can look the following way
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * connect( char **words, size_t n )
{
char *s = calloc( 1, sizeof( char ) );
if ( s != NULL )
{
size_t pos = 0;
for ( size_t i = 0; s != NULL && i < n; i++ )
{
size_t length = strlen( words[i] );
char *tmp = realloc( s, pos + length + 1 );
if ( tmp != NULL )
{
s = tmp;
strcpy( s + pos, words[i] );
pos += length;
}
else
{
free( s );
s = NULL;
}
}
}
return s;
}
int main( void )
{
char * s[] = { "Hello", " ", "World" };
char *p = connect( s, sizeof( s ) / sizeof( *s ) );
if ( p != NULL ) puts( p );
free( p );
}
In addition to using strcpy, you can also use sprintf. Each of the functions in the printf family returns the number of characters actually output allowing you to compute an offset in your final string without an additional function call. Now, there is nothing wrong with using a strcpy/strlen approach, and in fact, that is probably the preferred approach, but be aware that there are always multiple ways of doing things within the parameters you have given. Also note that the printf family offers a wealth of formatting benefits in the event you would need to include additional information along with the concatenation of strings.
For example, using sprintf to concatenate each string while saving the number of characters in each nc as the offset for writing the next string to the resulting buffer buf, while using a ternary operator to control the addition of a space between the words based on your loop counter, you could do something similar to the following:
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t total = 0; /* total number of characters required */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) /* get total required length */
total += strlen (p[i]) + 1; /* including spaces between */
if (!(buf = malloc (total + 1))) /* allocate/validate mem */
return buf; /* return NULL on error */
for (int i = 0; i < n; i++) /* add each word to buf, save nc */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
note: each memory allocation with malloc, calloc or realloc should be validated to insure it succeeds, and the error handled in the event of failure. (here NULL is returned if allocation fails).
Putting that together in a short example, you could do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t total = 0; /* total number of characters required */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) /* get total required length */
total += strlen (p[i]) + 1; /* including spaces between */
if (!(buf = malloc (total + 1))) /* allocate/validate mem */
return buf; /* return NULL on error */
for (int i = 0; i < n; i++) /* add each word to buf, save nc */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
int main (void) {
char *sa[] = { "My", "dog", "has", "too many", "fleas." },
*result = compress (sa, sizeof sa/sizeof *sa);
if (result) { /* check return */
printf ("result: '%s'\n", result); /* print string */
free (result); /* free memory */
}
return 0;
}
Example Use/Output
$ ./bin/strcat_sprintf
result: 'My dog has too many fleas.'
Memory/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to write beyond/outside the bounds of your allocated block of memory, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/strcat_sprintf
==27595== Memcheck, a memory error detector
==27595== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==27595== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==27595== Command: ./bin/strcat_sprintf
==27595==
result: 'My dog has too many fleas.'
==27595==
==27595== HEAP SUMMARY:
==27595== in use at exit: 0 bytes in 0 blocks
==27595== total heap usage: 1 allocs, 1 frees, 28 bytes allocated
==27595==
==27595== All heap blocks were freed -- no leaks are possible
==27595==
==27595== For counts of detected and suppressed errors, rerun with: -v
==27595== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have any additional questions.
compress with a Single Loop
As mentioned in the comment to MarianD's answer, you can use a single loop, reallocating your buffer with the addition of each word to the final string, but that is less efficient than getting the total number of characters required and then allocating once. However, there are many occasions where that is exactly what you will be required to do. Basically, you will simply get the length of each word and then allocate memory for that word (and the space between it and the next and for the nul-byte) using realloc instead of malloc (or calloc). realloc acts just like malloc for the first allocation, thereafter it resizes the buffer maintaining its current contents.
note: never realloc the buffer directly (e.g. buf = realloc (buf, newsize);), instead, always use a temporary pointer. Why? IF realloc fails, NULL is returned by realloc which causes you to lose the reference to your original buf (e.g. it will result in buf = NULL;), meaning that the address for your original buf is lost (and you have created a memory leak).
Putting that together, you could do something like the following:
char *compress (char **p, int n)
{
char *buf = NULL; /* buffer to hold concatendated string */
size_t bufsz = 0; /* current allocation size for buffer */
int nc = 0; /* number of chars added (counter) */
for (int i = 0; i < n; i++) { /* add each word to buf */
size_t len = strlen (p[i]) + 1; /* get length of word */
void *tmp = realloc (buf, bufsz + len); /* realloc buf */
if (!tmp) /* validate reallocation */
return buf; /* return current buffer */
buf = tmp; /* assign reallocated block to buffer */
bufsz += len; /* increment bufsz to current size */
nc += sprintf (buf + nc, i ? " %s" : "%s", p[i]);
}
*(buf + nc) = 0; /* affirmatively nul-terminate buf */
return buf;
}
Memory/Error Check
$ valgrind ./bin/strcat_sprintf_realloc
==28175== Memcheck, a memory error detector
==28175== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28175== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==28175== Command: ./bin/strcat_sprintf_realloc
==28175==
result: 'My dog has too many fleas.'
==28175==
==28175== HEAP SUMMARY:
==28175== in use at exit: 0 bytes in 0 blocks
==28175== total heap usage: 5 allocs, 5 frees, 68 bytes allocated
==28175==
==28175== All heap blocks were freed -- no leaks are possible
==28175==
==28175== For counts of detected and suppressed errors, rerun with: -v
==28175== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
note: now there are 5 allocations instead of 1.
Let me know if you have any questions.
I have a struct
typedef struct
{
int size; //size of array
int array*
}
How do I allocate memory for the int array using the size variable and malloc?
The answer to your question will depend on whether you are declaring a struct or a pointer to struct. In the event you declare a struct (e.g. mystruct s), then you only need to allocate memory for s.size elements in s.array. e.g.:
typedef struct mystruct {
int size;
int *array;
} mystruct;
...
mystruct s;
s.size = 5;
/* allocating array based on size */
s.array = malloc (s.size * sizeof *s.array);
if (!s.array) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
note: you must validate your allocation succeeded and malloc actually returned a valid address each time you call malloc. (you can create a function that does this to cut down on the typing). You then only need free s.array when you are done.
However, if you declare a pointer to struct (e.g. mystruct *msp = NULL;) you now have to allocate memory for both msp and msp->array. Example:
mystruct *msp = NULL;
msp = malloc (sizeof *msp);
if (!msp) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
msp->size = 5;
/* allocating array based on size */
msp->array = malloc (msp->size * sizeof *msp->array);
if (!msp->array) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
You must free both when you are done.
The following is a quick example showing the allocation, use and freeing of memory for array in both circumstances:
#include <stdio.h>
#include <stdlib.h>
typedef struct mystruct {
int size;
int *array;
} mystruct;
int main (void) {
size_t i = 0;
size_t nelements = 0;
int rd = 0;
/*
* declaring a struct mystruct
*/
mystruct s;
s.size = 5;
/* allocating array based on size */
s.array = malloc (s.size * sizeof *s.array);
if (!s.array) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
/* fill array */
for (rd = 0; rd < s.size; rd++)
if (scanf ("%d", &s.array[nelements]) == 1)
nelements++;
for (i = 0; i < nelements; i++)
printf (" s.array[%zu] = %d\n", i, s.array[i]);
/* free allocated memory */
free (s.array);
putchar ('\n');
/*
* declaring a pointer to mystruct
*/
mystruct *msp = NULL;
/* allocate memory for msp (mystruct pointer) */
msp = malloc (sizeof *msp);
if (!msp) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
msp->size = 5;
/* allocating array based on size */
msp->array = malloc (msp->size * sizeof *msp->array);
if (!msp->array) {
fprintf (stderr, "error: virtual memory exhausted.\n");
return 1;
}
/* fill array */
rd = 0;
nelements = 0;
for (rd = 0; rd < msp->size; rd++)
if (scanf ("%d", &msp->array[nelements]) == 1)
nelements++;
for (i = 0; i < nelements; i++)
printf (" msp->array[%zu] = %d\n", i, msp->array[i]);
/* free allocated memory */
free (msp->array);
free (msp);
return 0;
}
Example Use/Output
$ printf "2\n4\n6\n8\n10\n12\n14\n16\n18\n20\n" | ./bin/struct_alloc_int
s.array[0] = 2
s.array[1] = 4
s.array[2] = 6
s.array[3] = 8
s.array[4] = 10
msp->array[0] = 12
msp->array[1] = 14
msp->array[2] = 16
msp->array[3] = 18
msp->array[4] = 20
Memory Error Check
In any code you write that dynamically allocates memory, it is imperative that your use a memory error checking program. For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are simple to use. Just run your program through it.
$ printf "2\n4\n6\n8\n10\n12\n14\n16\n18\n20\n" | valgrind ./bin/struct_alloc_int
==20515== Memcheck, a memory error detector
==20515== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==20515== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==20515== Command: ./bin/struct_alloc_int
==20515==
s.array[0] = 2
<snip>
msp->array[4] = 20
==20515==
==20515== HEAP SUMMARY:
==20515== in use at exit: 0 bytes in 0 blocks
==20515== total heap usage: 3 allocs, 3 frees, 56 bytes allocated
==20515==
==20515== All heap blocks were freed -- no leaks are possible
==20515==
==20515== For counts of detected and suppressed errors, rerun with: -v
==20515== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
int *ptr;
ptr = malloc(sizeof *ptr * size);
//can now reference ptr[0], ptr[1], ... ptr[size-1].
What the above code does: When you allocate memory for an int array, you allocate 4 bytes of memory (sizeof(int)) for each element you need. So when you malloc, you malloc the size of the element multiplied by the number of elements you need.
You can create a function for initializing the struct, you can create one like this:
typedef struct {
int size; //size of array
int *array;
} mystruct;
mystruct * create_mystruct(int size) {
mystruct * st = (mystruct*) malloc(sizeof(mystruct));
st->size = size;
st->array = (int *) malloc(sizeof(int) * size);
return st;
}
Here is a working idone as an example.