I have the following two functions which takes an arrays of strings and makes them lowercase (in-place) --
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
void to_lower(char ** strings) {
char * original_string;
char * lower_string;
for (int i=0; (original_string=strings[i]) != NULL; i++) {
lower_string = malloc(strlen(original_string + 1) * sizeof(char));
for (int j=0; j<=strlen(original_string); j++) {
lower_string[j] = tolower(original_string[j]);
}
strings[i]=lower_string;
}
}
int main(void) {
char * strings[] = {"Hello", "Zerotom", "new", NULL };
to_lower(strings);
to_lower(strings); // this and successive calls won't change
to_lower(strings); // anything but are here to try and understand malloc
to_lower(strings);
to_lower(strings);
return 0;
}
At the beginning of the main function before to_lower is called, how much memory is consumed? My guess was 16 bytes from the array of chars (15 chars + 1 null byte at end).
After to_lower has run 5 times and before the function is returned, how much memory has been consumed? Where should I be "free"-ing the strings that are being passed into the function (as my thought was calling malloc every time a string is copied/lower-cased it creates that much additional memory but never frees anything.
Does the to_lower function look ok, or how can it be modified so that it doesn't leak memory if it currently is?
You are wrapping yourself around the axle (confusing yourself) by combining the allocation and conversion to lower into a single void to_lower(char ** strings) function. Just as you have found, if you want to call the function twice on the same object, you have to free the memory you allocated to hold the lowercase strings in between calls -- but then you have lost the pointers to your original strings..
While there is nothing wrong with combining multiple operations in a function, you do have to step back and make sure what you are doing makes sense and won't cause more problems than it solves.
Your allocation and copying of strings is required before you modify the strings contained in strings because you initialize strings as an array of pointers to string-literals. String-literal are immutable (on all but a very few systems) created in read-only memory (generally the .rodata section of the executable). Attempting to modify a string-literal will just about guarantee a SegFault (on all but the quirky few systems)
Further, how are you going to get the original strings back if you have already overwritten the pointer addresses to the originals with pointers to allocated memory holding the lower-case results? (not to mention the tracking headache you create by replacing pointers to literals with pointers to allocated memory as far as when it is okay to free those pointers).
Here it is far better to leave you original strings untouched and simply allocate a copy of the original (by allocating pointers, including one for the sentinel value, and allocating storage for each of the original strings and then copy the original strings before converting to lowercase. This solves your problem with memory leaks as well as the problem with losing your original pointers to the string literals. You can free the lowercase strings as needed and you can always make another copy of the originals to send to your conversion function again.
So how would you go about implementing this? The easiest way is just to declare a pointer to pointer to char (e.g. a double-pointer) to which you can assign a block of memory for any number of pointers you like. In this case just allocate the same number of pointers as you have in the strings array, e.g.:
char *strings[] = {"Hello", "Zerotom", "new", NULL };
size_t nelem = *(&strings + 1) - strings; /* number of pointers */
/* declare & allocate nelem pointers */
char **modstrings = malloc (nelem * sizeof *modstrings);
if (!modstrings) { /* validate EVERY allocation */
perror ("malloc-modstrings");
}
(note: you can also use sizeof strings / sizeof *strings to obtain the number of elements)
Now that you have modstrings assigned a block of memory holding the same number of pointers as you have in strings, you can simply allocate blocks of memory sufficient to hold each of the string literals and assign the starting address for each block to successive pointers in modstrings setting the last pointer NULL as your sentinel, e.g.
void copy_strings (char **dest, char * const *src)
{
while (*src) { /* loop over each string */
size_t len = strlen (*src); /* get length */
if (!(*dest = malloc (len + 1))) { /* allocate/validate */
perror ("malloc-dest"); /* handle error */
exit (EXIT_FAILURE);
}
memcpy (*dest++, *src++, len + 1); /* copy *src to *dest (advance) */
}
*dest = NULL; /* set sentinel NULL */
}
(note: by passing the src parameter as char * const *src instead of just char **src, you can indicate to the compiler that src will not be changed allowing further optimizations by the compiler. restrict would be similar, but that discussion is left to another day)
Your to_lower function then reduces to:
void to_lower (char **strings) {
while (*strings) /* loop over each string */
for (char *p = *strings++; *p; p++) /* loop over each char */
*p = tolower (*p); /* convert to lower */
}
As a convenience, since you know you will want to copy strings to modstrings before each call to to_lower, you can combine both functions into a single wrapper (that does make sense to combine), e.g.
void copy_to_lower (char **dest, char * const *src)
{
copy_strings (dest, src); /* just combine functions above into single */
to_lower (dest);
}
(you could even add the print_array and free_strings above as well if you always want to do those operations in a single call as well -- more later)
In between each copy_to_lower and print_array of modstrings you will need to free the storage assigned to each pointer so you do not leak memory when you call copy_to_lower again. A simple free_strings function could be:
void free_strings (char **strings)
{
while (*strings) { /* loop over each string */
free (*strings); /* free it */
*strings++ = NULL; /* set pointer NULL (advance to next) */
}
}
You can now allocate, copy, convert to lower, print, and free as many times as you like in main(). you would simply make repeated calls to:
copy_to_lower (modstrings, strings); /* copy_to_lower to modstrings */
print_array (modstrings); /* print modstrings */
free_strings (modstrings); /* free strings (not pointers) */
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
...
Now recall, you are freeing the storage for each string when you call free_strings, but you are leaving the block of memory containing the pointers assigned to modstrings. So to complete your free of all memory you have allocated, don't forget to free the pointers, e.g.
free (modstrings); /* now free pointers */
Putting it altogether into an example you could do the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void print_array (char **strings)
{
while (*strings)
printf ("%s, ", *strings++);
putchar ('\n');
}
void free_strings (char **strings)
{
while (*strings) { /* loop over each string */
free (*strings); /* free it */
*strings++ = NULL; /* set pointer NULL (advance to next) */
}
}
void copy_strings (char **dest, char * const *src)
{
while (*src) { /* loop over each string */
size_t len = strlen (*src); /* get length */
if (!(*dest = malloc (len + 1))) { /* allocate/validate */
perror ("malloc-dest"); /* handle error */
exit (EXIT_FAILURE);
}
memcpy (*dest++, *src++, len + 1); /* copy *src to *dest (advance) */
}
*dest = NULL; /* set sentinel NULL */
}
void to_lower (char **strings) {
while (*strings) /* loop over each string */
for (char *p = *strings++; *p; p++) /* loop over each char */
*p = tolower (*p); /* convert to lower */
}
void copy_to_lower (char **dest, char * const *src)
{
copy_strings (dest, src); /* just combine functions above into single */
to_lower (dest);
}
int main(void) {
char *strings[] = {"Hello", "Zerotom", "new", NULL };
size_t nelem = *(&strings + 1) - strings; /* number of pointers */
/* declare & allocate nelem pointers */
char **modstrings = malloc (nelem * sizeof *modstrings);
if (!modstrings) { /* validate EVERY allocation */
perror ("malloc-modstrings");
}
copy_to_lower (modstrings, strings); /* copy_to_lower to modstrings */
print_array (modstrings); /* print modstrings */
free_strings (modstrings); /* free strings (not pointers) */
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
free (modstrings); /* now free pointers */
}
Example Use/Output
$ ./bin/tolower_strings
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
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 access memory or write beyond/outside the bounds of your allocated block, 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/tolower_strings
==5182== Memcheck, a memory error detector
==5182== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5182== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==5182== Command: ./bin/tolower_strings
==5182==
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
==5182==
==5182== HEAP SUMMARY:
==5182== in use at exit: 0 bytes in 0 blocks
==5182== total heap usage: 13 allocs, 13 frees, 104 bytes allocated
==5182==
==5182== All heap blocks were freed -- no leaks are possible
==5182==
==5182== For counts of detected and suppressed errors, rerun with: -v
==5182== 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.
Now this is a long post, but you have made progress on learning dynamic allocation. It will take you a while to digest it all, but if you have further questions just let me know.
Does the to_lower function look ok, or how can it be modified so that
it doesn't leak memory if it currently is?
As pointed out by #chux in comments, you need to add 1 to the len of orginal_string, not to the pointer itself.
Regarding your question, yes, it leaks, each call to malloc wants a call to free. The problem here is: you are not allowed to call free on the initial values since they are filled with string-literals.
A posible solution is:
extern char *strdup(const char *);
static char *dup(const char *str)
{
char *res = strdup(str);
if (res == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
return res;
}
int main(void)
{
char *strings[] = {
dup("Hello"),
dup("Zerotom"),
dup("new"),
NULL
};
...
Now you can call to_lower and you don't need to malloc inside the function, just call free for each element at the very end when the array is no longer needed.
Notice that strdup is not part of the standard (but is avaliable on many implementations)
Every time to_lower() is called, you are replacing all string literals with dynamic memory pointers.
If you are calling to_lower() again without freeing existing memory, there is a memory leak.
lower_string = malloc(strlen(original_string + 1) * sizeof(char));
for (int j=0; j<=strlen(original_string); j++) {
lower_string[j] = tolower(original_string[j]);
}
strings[i]=lower_string;
So that when strings[] array is no longer needed, you should free all its memory.
E.g.
for (int i=0; strings[i] != NULL; i++) {
free(strings[i]);
strings[i] = NULL;
}
As an alternative to {"Hello", "Zerotom", "new", NULL }; and malloc() and friends, form the array of pointers char * strings[] to be initialized with pointers to modifiable data.
Since C99, use compound literals.
void inplace_strtolower(char * s) {
while (*s) {
*s = (char) tolower((unsigned char ) *s);
s++;
}
}
// "Non-const string literal"
// Compound literal from string literal"
#define NCSL(sl) ((char[sizeof(sl)]) { sl })
int main(void) {
char * strings[] = {NCSL("Hello"), NCSL("Zerotom"), NCSL("new"), NULL};
inplace_strtolower(strings[0]);
inplace_strtolower(strings[1]);
inplace_strtolower(strings[2]);
puts(strings[0]);
puts(strings[1]);
puts(strings[2]);
return 0;
}
Output
hello
zerotom
new
Related
When we allocating memory spaces for a string, do the following 2 ways give the same result?
char *s = "abc";
char *st1 = (char *)malloc(sizeof(char)*strlen(s));
char *st2 = (char *)malloc(sizeof(s));
In other words, does allocate the memory based on the size of its characters give the same result as allocating based on the size of the whole string?
If I do use the later method, is it still possible for me to add to that memory spaces character by character such as:
*st = 'a';
st++;
*st = 'b';
or do I have to add a whole string at once now?
Let's see if we can't get you straightened out on your question and on allocating (and reallocating) storage. To begin, when you declare:
char *s = "abc";
You have declared a pointer to char s and you have assigned the starting address for the String Literal "abc" to the pointer s. Whenever you attempt to use sizeof() on a_pointer, you get sizeof(a_pointer) which is typically 8-bytes on x86_64 (or 4-bytes on x86, etc..)
If you take sizeof("abc"); you are taking the size of a character array with size 4 (e.g. {'a', 'b', 'c', '\0'}), because a string literal is an array of char initialized to hold the string "abc" (including the nul-terminating character). Also note, that on virtually all systems, a string literal is created in read-only memory and cannot be modified, it is immutable.
If you want to allocate storage to hold a copy of the string "abc", you must allocate strlen("abc") + 1 characters (the +1 for the nul-terminating character '\0' -- which is simply ASCII 0, see ASCII Table & Description.
Whenever you allocate 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. So if you allocate for char *st = malloc (len + 1); characters, you do not want to iterate with the pointer st (e.g. no st++). Instead, declare a second pointer, char *p = st; and you are free to iterate with p.
Also, in C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.
If you want to add to an allocation, you use realloc() which will create a new block of memory for you and copy your existing block to it. When using realloc(), you always reallocate using a temporary pointer (e.g. don't st = realloc (st, new_size);) because if when realloc() fails, it returns NULL and if you assign that to your pointer st, you have just lost the original pointer and created a memory leak. Instead, use a temporary pointer, e.g. void *tmp = realloc (st, new_size); then validate realloc() succeeds before assigning st = tmp;
Now, reading between the lines that is where you are going with your example, the following shows how that can be done, keeping track of the amount of memory allocated and the amount of memory used. Then when used == allocated, you reallocate more memory (and remembering to ensure you have +1 bytes available for the nul-terminating character.
A short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define THISMANY 23
int main (void) {
char *s = "abc", *st, *p; /* string literal and pointer st */
size_t len = strlen(s), /* length of s */
allocated = len + 1, /* number of bytes in new block allocated */
used = 0; /* number of bytes in new block used */
st = malloc (allocated); /* allocate storage for copy of s */
p = st; /* pointer to allocate, preserve st */
if (!st) { /* validate EVERY allocation */
perror ("malloc-st");
return 1;
}
for (int i = 0; s[i]; i++) { /* copy s to new block of memory */
*p++ = s[i]; /* (could use strcpy) */
used++; /* advance counter */
}
*p = 0; /* nul-terminate copy */
for (size_t i = 0; i < THISMANY; i++) { /* loop THISMANY times */
if (used + 1 == allocated) { /* check if realloc needed (remember '\0') */
/* always realloc using temporary pointer */
void *tmp = realloc (st, 2 * allocated); /* realloc 2X current */
if (!tmp) { /* validate EVERY reallocation */
perror ("realloc-st");
break; /* don't exit, original st stil valid */
}
st = tmp; /* assign reallocated block to st */
allocated *= 2; /* update allocated amount */
}
*p++ = 'a' + used++; /* assign new char, increment used */
}
*p = 0; /* nul-terminate */
printf ("result st : %s\n" /* output final string, length, allocated */
"length st : %zu bytes\n"
"final size : %zu bytes\n", st, strlen(st), allocated);
free (st); /* don't forget to free what you have allocated */
}
Example Use/Output
$ ./bin/sizeofs
result st : abcdefghijklmnopqrstuvwxyz
length st : 26 bytes
final size : 32 bytes
Look things over and let me know if this answered your questions, and if not, leave a comment and I'm happy to help further.
If you are still shaky on what a pointer is, and would like more information, here are a few links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)
I tried to increase a double pointer buffer in another method/function. However, the size of the allocated buffer does not changes. Here is the code I tried.
#include <stdio.h>
#include <stdlib.h>
void change_buffer_size(char ** buffer)
{
*buffer = realloc(*buffer, sizeof(char) * 2);
}
int main()
{
char **buffer = malloc(sizeof(char) * 1);
*buffer[0] = 'H';
change_buffer_size(buffer);
*buffer[1] = 'i';
printf("%s\n", *buffer);
return 0;
}
I get the Segmentation fault (core dumped) error.
char **buffer = malloc(sizeof(char) * 1);
This is wrong. You now have a char**, so the thing that it points to is a char*, but there's only enough room in it for a char. You also only allocated one layer of the double pointer.
*buffer[0] = 'H';
This line causes the segfault because of the above problems. It's trying to write to memory in an undefined location.
The best way to fix this is to just allocate the first layer normally, use & where necessary, and only use malloc for the second layer.
Also, %s doesn't stop writing until it sees a null byte, so you need to allocate and write one of them. Here's how you fix it all:
#include <stdio.h>
#include <stdlib.h>
void change_buffer_size(char ** buffer)
{
*buffer = realloc(*buffer, sizeof(char) * 3);
}
int main()
{
char *buffer = malloc(sizeof(char) * 1);
buffer[0] = 'H';
change_buffer_size(&buffer);
buffer[1] = 'i';
buffer[2] = '\0';
printf("%s\n", buffer);
return 0;
}
You already have a good answer by #JosephSible but there is one further point that needs making about the use of realloc. I've alluded to this in the comment under the original question. When using realloc, you must always realloc using a temporary pointer to capture the return of realloc.
Why? When (not if) realloc fails, it returns NULL. If you assign the return directly to the pointer you are attempting to reallocate for, you overwrite the pointer to your existing block of memory with NULL losing your reference to the original block creating a memory leak. For example, you do not want to:
*buffer = realloc (*buffer, 2); /* sizeof(char) is always 1 */
Instead, use a temporary pointer and validate the reallocation succeeds before assigning the reallocated block to your original pointer, e.g.
void * tmp = realloc (*buffer, 2);
if (!tmp) { /* validate EVERY allocation & reallocation */
perror ("realloc-*buffer");
exit (EXIT_FAILURE); /* or handle as desired, e.g return NULL, etc.. */
}
*buffer = tmp; /* now assign the reallocated block to your pointer */
A couple of comments on your original post. Recall in C a string must end with a nul-terminating character. You cannot simply assign buffer[0] = 'H'; and treat buffer as a string. The nul-termianting character ('\0', or simply 0) must follow, so you would need buffer[1] = 0; before calling printf("%s\n", *buffer);
Avoid using Magic-Numbers in your code. Your change_buffer_size() function hardcodes the reallocation to size using the magic-number 2. (not very useful). Instead, at least pass the desired size as a parameter so your function is reusable, e.g.
char *change_buffer_size (char **buffer, size_t nchar)
{
void *tmp = realloc (*buffer, nchar * sizeof **buffer);
if (!tmp) { /* validate EVERY allocation/reallocation */
perror ("change_buffer_size()-realloc");
return NULL;
}
return *buffer = tmp; /* assign new block to *buffer, return */
}
(note: changing the return type to char* allows you to indicate success/failure of the function through the return as well as having direct access to the reallocated block of memory on success)
Now is you want to reallocate your buffer to 2-characters, just pass 2 as nchar, etc.. That combined with a short example that reallocates and adds a character to your buffer at a time (while ensuring it is always nul-terminated) could be something like the following:
#include <stdio.h>
#include <stdlib.h>
char *change_buffer_size (char **buffer, size_t nchar)
{
void *tmp = realloc (*buffer, nchar * sizeof **buffer);
if (!tmp) { /* validate EVERY allocation/reallocation */
perror ("change_buffer_size()-realloc");
return NULL;
}
return *buffer = tmp; /* assign new block to *buffer, return */
}
int main (void) {
size_t nchar = 1; /* character counter */
char *str = "hello world!", *buffer = NULL;
for (int i = 0; str[i]; i++) {
if (!change_buffer_size(&buffer, nchar + 1)) /* alloc nchar + 1 */
return 1;
buffer[nchar-1] = str[i]; /* copy char from str to buffer */
buffer[nchar++] = 0; /* nul-terminate buffer */
printf ("buffer: '%s'\n", buffer); /* print current buffer contents */
}
free (buffer); /* don't forget to free what you allocate */
}
(note: don't forget to free() the memory you allocate. Yes, here it will be freed on program exit, but build good habits early -- you will not always be working in main())
Example Use/Output
$ ./bin/realloccharbuf
buffer: 'h'
buffer: 'he'
buffer: 'hel'
buffer: 'hell'
buffer: 'hello'
buffer: 'hello '
buffer: 'hello w'
buffer: 'hello wo'
buffer: 'hello wor'
buffer: 'hello worl'
buffer: 'hello world'
buffer: 'hello world!'
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 ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, 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/realloccharbuf
==19740== Memcheck, a memory error detector
==19740== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19740== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==19740== Command: ./bin/realloccharbuf
==19740==
buffer: 'h'
buffer: 'he'
buffer: 'hel'
buffer: 'hell'
buffer: 'hello'
buffer: 'hello '
buffer: 'hello w'
buffer: 'hello wo'
buffer: 'hello wor'
buffer: 'hello worl'
buffer: 'hello world'
buffer: 'hello world!'
==19740==
==19740== HEAP SUMMARY:
==19740== in use at exit: 0 bytes in 0 blocks
==19740== total heap usage: 13 allocs, 13 frees, 1,114 bytes allocated
==19740==
==19740== All heap blocks were freed -- no leaks are possible
==19740==
==19740== For counts of detected and suppressed errors, rerun with: -v
==19740== 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 questions.
I need to write a function called MakeString. The function returns a pointer to a string, which contains one word composed of each row of the small matrix in order, so that each line break will be expressed
as a single space between the words In the string. (After the last word there will be no space.)
Inference: In the function there is no use of [], but executes by working with pointers.
Function. In addition, trips should be carried out with the voters, meaning that they will actually move to vote for each other
Whatever it takes, and will not stay in the same location all the time.
The 'answer' that the function returns, which is a pointer, will be input into a pointer in MAIN.
I tried to do the function, but It NOT like instruction and not good...
#define SIZE 4
static char allocbuf[SIZE][];
static char *allocp = allocbuf;
char matrix[SIZE][SIZE]
{
{U,N,T,E},
{C,P,G,X},
{D,L,A,B},
{J,T,N,N}
};
char MakeString(int n) /*return pointer to n charachters*/
{
if (allocbuf + SIZE - allocp >=n)
{
allocp += n;
return allocp - n;
}
else
return 0;
}
For example:
Small matrix:
U N T E
C P G X
D L A B
J T N N
pStr = UNTE CPGX DLAB JTNN
Thanks (:
If I understand your question, you want write a function to read the characters from matrix (a 2D array of char) into an allocated string placing a space between each rows worth of characters and returning the nul-terminated string back to the calling function. You need to do this using pointers and without array [index] notation.
To begin, your declaration of matrix is wrong. E isn't a character, it is a variable. 'E' is a character literal. (note the single-quotes) So a proper declaration of matrix would be:
char matrix[SIZE][SIZE] = { {'U','N','T','E'}, /* don't use globals */
{'C','P','G','X'}, /* declare in main and */
{'D','L','A','B'}, /* pass as a parameter */
{'J','T','N','N'} };
(note: simply char matrix[][SIZE] = {{...}}; is sufficient, where the number of rows will be sized based on your initialization)
As noted in the comment, avoid the use of global variables unless absolutely necessary. (very limited cases -- not here). Instead, declare matrix in the scope where it is required and pass matrix as a parameter to any function that needs to process the data. By contrast, defining is constant with #define is perfectly correct, and you should define constants as needed to avoid using magic-numbers in your code.
Since matrix is a 2D array, to pass it as a parameter, you must include the number of columns as part of the parameter passed. You can either declare the parameter as char matrix[SIZE][SIZE] or equivalently as char (*matrix)[SIZE] reflecting the fact that the first level of indirection is converted to a pointer to the first element on access. See: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) (paying attention to the 4-exceptions)
Within your makestring() function you must allocate storage of at least SIZE * SIZE + SIZE (space for each character + 3 spaces + the nul-terminating character). Assigning the starting address of your new block of memory to a pointer, and then creating a second pointer to the block will allow you to iterate over it, copying characters to it -- while preserving a pointer to the beginning.
Putting those pieces together, you could do something similar to:
char *makestring (char (*a)[SIZE])
{
char *str = malloc (SIZE * SIZE + SIZE), *p = str; /* allocate */
if (!str) { /* validate EVERY allocation */
perror ("malloc-str");
return NULL;
}
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = *(*(a + i) + j); /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to allocated string */
}
(note: while not an error, C generally avoids the use of camelCase or MixedCase variable names in favor of all lower-case while reserving upper-case names for use with macros and constants.)
Putting it altogether in a short example, you could do:
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char *makestring (char (*a)[SIZE])
{
char *str = malloc (SIZE * SIZE + SIZE), *p = str; /* allocate */
if (!str) { /* validate EVERY allocation */
perror ("malloc-str");
return NULL;
}
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = *(*(a + i) + j); /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to allocated string */
}
int main (void) {
char matrix[SIZE][SIZE] = { {'U','N','T','E'}, /* don't use globals */
{'C','P','G','X'}, /* declare in main and */
{'D','L','A','B'}, /* pass as a parameter */
{'J','T','N','N'} },
*str;
if ((str = makestring (matrix))) { /* validate call to makestring */
printf ("str: '%s'\n", str); /* output string */
free (str); /* free allocated memory */
}
}
(note: don't forget to free the memory you allocate. While it will be freed on program exit, get in the habit of tracking your allocations and ensuring all blocks you allocate are freed)
Example Use/Output
$ ./bin/makestring
str: 'UNTE CPGX DLAB JTNN'
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 access memory or write beyond/outside the bounds of your allocated block, 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/makestring
==6576== Memcheck, a memory error detector
==6576== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6576== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6576== Command: ./bin/makestring
==6576==
str: 'UNTE CPGX DLAB JTNN'
==6576==
==6576== HEAP SUMMARY:
==6576== in use at exit: 0 bytes in 0 blocks
==6576== total heap usage: 1 allocs, 1 frees, 20 bytes allocated
==6576==
==6576== All heap blocks were freed -- no leaks are possible
==6576==
==6576== For counts of detected and suppressed errors, rerun with: -v
==6576== 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.
You need to specify the size of allocbuf so it can hold the entire result:
char allocbuf[SIZE * (SIZE + 1)];
There's no need for allocp, because the array name will decay to a pointer when used in calculations. In MakeString, you need to loop over the rows and characters of matrix, copying them to allocbuf.
char *MakeString()
for (int i = 0; i < SIZE; i++) {
memcpy(allocbuf + i * SIZE, matrix + i, SIZE);
if (i < SIZE - 1) {
// write space between rows
*(allocbuf + i * SIZE + SIZE) = ' ';
} else {
// write null at end
*(allocbuf + i * SIZE + SIZE) = 0;
}
}
return allocbuf;
}
The instructions don't mention the n argument to MakeString(), so I removed it.
I am creating a function for a code and the code uses the function that outputs to a file pointer like for example,
number *base6 = intToNumber(50, 6);
Here is the code I have so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
int iNum;
int base;
char* sNum;
} number;
number * intToNumber(int nnum, int nbase) {
number * theNumbers;
//theNumbers= (number*)malloc(10*sizeof(number));
if (theNumbers = NULL) {
printf("\n\nNo\n\n");
exit(1);
}
theNumbers->iNum = nnum;
theNumbers->base = nbase;
}
You are beginning to think along the correct lines, but your handling of allocation for your theNumbers (you have commented) is just step one. When you allocate theNumbers, the pointer theNumbers->sNum is created -- but it is an Uninitialized Pointer that holds an indeterminate address as its value. (e.g. it points nowhere you have any ability to make use of). Think about your struct (typedef)
typedef struct {
int iNum; /* automatic storage types */
int base;
char *sNum; /* a pointer - hold address to something else */
} number; /* must point to valid memory addr */
When you allocate for one of those, you allocate 2 integer values and one character pointer that have automatic storage type and can be assigned values. While iNum and base are integer values and can be assigned immediate values like 50 and 6, sNum by contrast is a pointer and can only be assigned a valid memory address where something else is stored.
Normally, to make use of a pointer, you allocate a new block of memory, fill that memory with whatever is needed for the type, and then assign the starting address for that new block of memory to your pointer (sNum here). So now your pointer will hold the address of (e.g. point to) a valid block of memory containing values usable by that object type. (char*, a pointer to a char, here)
Your intToNumber function takes only int nnum and int nbase as parameters, so after allocating for your struct, you can only initialize theNumbers->iNum = nnum; and theNumbers->base = nbase;, but have nothing to size or initialize sNum with (it should therefore be set to NULL).
So you are close on your intToNumber, and all you need to do is return the pointer intToNumber after you have allocated storage for it (because following allocation it has allocated storage type which survives for the life of the program -- or until it is freed), e.g.
number *intToNumber (int nnum, int nbase) {
number *theNumbers;
theNumbers= malloc (sizeof *theNumbers); /* allocate */
if (theNumbers == NULL) { /* validate */
perror ("malloc-theNumbers");
return NULL;
}
theNumbers->iNum = nnum; /* initialize values */
theNumbers->base = nbase;
theNumbers->sNum = NULL;
return theNumbers; /* return pointer */
}
Now what to do about sNum? Well, it's up to you, but for example, you could create a separate function that takes your allocated struct and a character string as parameters, allocate for length + 1 bytes to hold the string (plus the nul-terminating character) assigning the starting address for the new bock to sNum, and then copying the string to the new block of memory, e.g.
/* allocate/set sNum member of n to s */
char *setsNum (number *n, const char *s)
{
if (!n) { /* validate n not NULL, return NULL on failure */
fputs ("error: struct parameter 'n' NULL.\n", stderr);
return NULL;
}
size_t len = strlen (s); /* get length */
n->sNum = malloc (len + 1); /* allocate storage (+1 byte) */
if (!n->sNum) { /* validate allocation */
perror ("malloc-sNum");
return NULL;
}
memcpy (n->sNum, s, len + 1); /* copy s to new block of memory */
return n->sNum; /* return pointer (convenience) */
}
(I suspect you will be filling it with your base6 conversion -- but that is left to you)
Other than freeing the memory when you are done with it, all that remains is a short example showing how to put it altogether. That you can do with something simple like:
int main (void) {
number *mynum = intToNumber (50, 6); /* declare/initialize mynum */
if (!mynum) /* validate succeeded */
return 1;
/* allocate/validate mynum->sNum, copy string */
if (!setsNum (mynum, "created with intToNumber (50, 6)")) {
free (mynum);
return 1;
}
/* output values held in mynum */
printf ("succeeded:\n iNum: %d\n base: %d\n str : %s\n",
mynum->iNum, mynum->base, mynum->sNum);
free (mynum->sNum); /* free allocated string */
free (mynum); /* free struct */
}
Example Use/Output
If you put the example together, you would get:
$ ./bin/struct_alloc_member
succeeded:
iNum: 50
base: 6
str : created with intToNumber (50, 6)
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 access memory or write beyond/outside the bounds of your allocated block, 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/struct_alloc_member
==15553== Memcheck, a memory error detector
==15553== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15553== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==15553== Command: ./bin/struct_alloc_member
==15553==
succeeded:
iNum: 50
base: 6
str : created with intToNumber (50, 6)
==15553==
==15553== HEAP SUMMARY:
==15553== in use at exit: 0 bytes in 0 blocks
==15553== total heap usage: 2 allocs, 2 frees, 49 bytes allocated
==15553==
==15553== All heap blocks were freed -- no leaks are possible
==15553==
==15553== For counts of detected and suppressed errors, rerun with: -v
==15553== 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.
The full example used was:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
int iNum; /* automatic storage types */
int base;
char *sNum; /* a pointer - hold address to something else */
} number; /* must point to valid memory addr */
number *intToNumber (int nnum, int nbase) {
number *theNumbers;
theNumbers= malloc (sizeof *theNumbers); /* allocate */
if (theNumbers == NULL) { /* validate */
perror ("malloc-theNumbers");
return NULL;
}
theNumbers->iNum = nnum; /* initialize values */
theNumbers->base = nbase;
theNumbers->sNum = NULL;
return theNumbers; /* return pointer */
}
/* allocate/set sNum member of n to s */
char *setsNum (number *n, const char *s)
{
if (!n) { /* validate n not NULL, return NULL on failure */
fputs ("error: struct parameter 'n' NULL.\n", stderr);
return NULL;
}
size_t len = strlen (s); /* get length */
n->sNum = malloc (len + 1); /* allocate storage (+1 byte) */
if (!n->sNum) { /* validate allocation */
perror ("malloc-sNum");
return NULL;
}
memcpy (n->sNum, s, len + 1); /* copy s to new block of memory */
return n->sNum; /* return pointer (convenience) */
}
int main (void) {
number *mynum = intToNumber (50, 6); /* declare/initialize mynum */
if (!mynum) /* validate succeeded */
return 1;
/* allocate/validate mynum->sNum, copy string */
if (!setsNum (mynum, "created with intToNumber (50, 6)")) {
free (mynum);
return 1;
}
/* output values held in mynum */
printf ("succeeded:\n iNum: %d\n base: %d\n str : %s\n",
mynum->iNum, mynum->base, mynum->sNum);
free (mynum->sNum); /* free allocated string */
free (mynum); /* free struct */
}
Supposing that the actual question is exactly what is presented in the title:
How do I return a struct from a function to a struct pointer?
The answer is that although a function can return a struct, it cannot do so to a struct pointer. Under no circumstance can you assign a struct to an object of of any pointer type. You can have a pointer to a struct, and you can have a struct that contains a pointer, but no struct is itself a pointer.
If, on the other hand, the question were about how to return a struct pointer then the answer would be "by using a return statement", the same way you return a value of any other type. For that to be useful, the pointer you return ought to be a valid one, but that's a separate question.
Why don't you pass in a pointer to the structure in the function such that the signature looks like void intToNumber(number *n)? And then you would have the implementation look something like
int main ()
{
number Numbers = {.sNum = malloc (25) };
// Do stuff here...
intToNumber(&Numbers);
// Do some more stuff...
}
Since you are pointing to the variable Numbers on the stack, you can manipulate those variable in the function intToNumber and have them available in the rest of the main function (or in whatever scope you decide to call it).
Is there a function which I can use that which will allow me to replace a specific texts.
For example:
char *test = "^Hello world^"; would be replaced with char *test = "<s>Hello world</s>";
Another example: char *test2 = "This is ~my house~ bud" would be replaced with char *test2 = "This is <b>my house</b> bud"
Before you can begin to replace substrings within a string, you have to understand what you are dealing with. In your example you want to know whether you can replace characters within a string, and you give as an example:
char *test = "^Hello world^";
By being declared and initialized as shown above test, is a string-literal created in read-only memory (on virtually all systems) and any attempt to modify characters stored in read-only memory invokes Undefined Behavior (and most likely a Segmentation Fault)
As noted in the comments, test could be declared and initialized as a character array, e.g. char test[] = "^Hello world^"; and insure that test is modifiable, but that does not address the problem where your replacement strings are longer than the substrings being replaced.
To handle the additional characters, you have two options (1) you can declare test[] to be sufficiently large to accommodate the substitutions, or (2) you can dynamically allocate storage for the replacement string, and realloc additional memory if you reach your original allocation limit.
For instance if you limit the code associated with test to a single function, you could declare test with a sufficient number of characters to handle the replacements, e.g.
#define MAXC 1024 /* define a constant for the maximum number of characters */
...
test[MAXC] = "^Hello world^";
You would then simply need to keep track of the original string length plus the number of character added with each replacement and insure that the total never exceeds MAXC-1 (reserving space for the nul-terminating character).
However, if you decided to move the replacement code to a separate function -- you now have the problem that you cannot return a pointer to a locally declared array (because the locally declared array is declared within the function stack space -- which is destroyed (released for reuse) when the function returns) A locally declared array has automatic storage duration. See: C11 Standard - 6.2.4 Storage durations of objects
To avoid the problem of a locally declared array not surviving the function return, you can simply dynamically allocate storage for your new string which results in the new string having allocated storage duration which is good for the life of the program, or until the memory is freed by calling free(). This allows you to declare and allocate storage for a new string within a function, make your substring replacements, and then return a pointer to the new string for use back in the calling function.
For you circumstance, a simple declaration of a new string within a function and allocating twice the amount of storage as the original string is a reasonable approach to take. (you still must keep track of the number of bytes of memory you use, but you then have the ability to realloc additional memory if you should reach your original allocation limit) This process can continue and accommodate any number of strings and substitutions, up to the available memory on your system.
While there are a number of ways to approach the substitutions, simply searching the original string for each substring, and then copying the text up to the substring to the new string, then copying the replacement substring allows you to "inch-worm" from the beginning to the end of your original string making replacement substitutions as you go. The only challenge you have is keeping track of the number of characters used (so you can reallocate if necessary) and advancing your read position within the original from the beginning to the end as you go.
Your example somewhat complicates the process by needing to alternate between one of two replacement strings as you work your way down the string. This can be handled with a simple toggle flag. (a variable you alternate 0,1,0,1,...) which will then determine the proper replacement string to use where needed.
The ternary operator (e.g. test ? if_true : if_false; can help reduce the number of if (test) { if_true; } else { if_false; } blocks you have sprinkled through your code -- it's up to you. If the if (test) {} format is more readable to you -- use that, otherwise, use the ternary.
The following example takes the (1) original string, (2) the find substring, (3) the 1st replacement substring, and (4) the 2nd replacement substring as arguments to the program. It allocates for the new string within the strreplace() function, makes the substitutions requested and returns a pointer to the new string to the calling function. The code is heavily commented to help you follow along, e.g.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* replace all instances of 'find' in 's' with 'r1' and `r2`, alternating.
* allocate memory, as required, to hold string with replacements,
* returns allocated string with replacements on success, NULL otherwise.
*/
char *strreplace (const char *s, const char *find,
const char *r1, const char *r2)
{
const char *p = s, /* pointer to s */
*sp = s; /* 2nd substring pointer */
char *newstr = NULL, /* newsting pointer to allocate/return */
*np = newstr; /* pointer to newstring to fill */
size_t newlen = 0, /* length for newstr */
used = 0, /* amount of allocated space used */
slen = strlen (s), /* length of s */
findlen = strlen (find), /* length of find string */
r1len = strlen (r1), /* length of replace string 1 */
r2len = strlen (r2); /* length of replace string 2 */
int toggle = 0; /* simple 0/1 toggle flag for r1/r2 */
if (s == NULL || *s == 0) { /* validate s not NULL or empty */
fputs ("strreplace() error: input NULL or empty\n", stderr);
return NULL;
}
newlen = slen * 2; /* double length of s for newstr */
newstr = calloc (1, newlen); /* allocate twice length of s */
if (newstr == NULL) { /* validate ALL memory allocations */
perror ("calloc-newstr");
return NULL;
}
np = newstr; /* initialize newpointer to newstr */
/* locate each substring using strstr */
while ((sp = strstr (p, find))) { /* find beginning of each substring */
size_t len = sp - p; /* length to substring */
/* check if realloc needed? */
if (used + len + (toggle ? r2len : r1len) + 1 > newlen) {
void *tmp = realloc (newstr, newlen * 2); /* realloc to temp */
if (!tmp) { /* validate realloc succeeded */
perror ("realloc-newstr");
return NULL;
}
newstr = tmp; /* assign realloc'ed block to newstr */
newlen *= 2; /* update newlen */
}
strncpy (np, p, len); /* copy from pointer to substring */
np += len; /* advance newstr pointer by len */
*np = 0; /* nul-terminate (already done by calloc) */
strcpy (np, toggle ? r2 : r1); /* copy r2/r1 string to end */
np += toggle ? r2len : r1len; /* advance newstr pointer by r12len */
*np = 0; /* <ditto> */
p += len + findlen; /* advance p by len + findlen */
used += len + (toggle ? r2len : r1len); /* update used characters */
toggle = toggle ? 0 : 1; /* toggle 0,1,0,1,... */
}
/* handle segment of s after last find substring */
slen = strlen (p); /* get remaining length */
if (slen) { /* if not at end */
if (used + slen + 1 > newlen) { /* check if realloc needed? */
void *tmp = realloc (newstr, used + slen + 1); /* realloc */
if (!tmp) { /* validate */
perror ("realloc-newstr");
return NULL;
}
newstr = tmp; /* assign */
newlen += slen + 1; /* update (not required here, know why? */
}
strcpy (np, p); /* add final segment to string */
*(np + slen) = 0; /* nul-terminate */
}
return newstr; /* return newstr */
}
int main (int argc, char **argv) {
const char *s = NULL,
*find = NULL,
*r1 = NULL,
*r2 = NULL;
char *newstr = NULL;
if (argc < 5) { /* validate required no. or arguments given */
fprintf (stderr, "error: insufficient arguments,\n"
"usage: %s <find> <rep1> <rep2>\n", argv[0]);
return 1;
}
s = argv[1]; /* assign arguments to poitners */
find = argv[2];
r1 = argv[3];
r2 = argv[4];
newstr = strreplace (s, find, r1, r2); /* replace substrings in s */
if (newstr) { /* validate return */
printf ("oldstr: %s\nnewstr: %s\n", s, newstr);
free (newstr); /* don't forget to free what you allocate */
}
else { /* handle error */
fputs ("strreplace() returned NULL\n", stderr);
return 1;
}
return 0;
}
(above, the strreplace function uses pointers to walk ("inch-worm") down the original string making replacement, but you can use string indexes and index variables if that makes more sense to you)
(also note the use of calloc for the original allocation. calloc allocates and sets the new memory to all zero which can aid in insuring you don't forget to nul-terminate your string, but note any memory added by realloc will not be zeroed -- unless you manually zero it with memset or the like. The code above manually terminates the new string after each copy, so you can use either malloc or calloc for the allocation)
Example Use/Output
First example:
$ ./bin/str_substr_replace2 "^Hello world^" "^" "<s>" "</s>"
oldstr: ^Hello world^
newstr: <s>Hello world</s>
Second example:
$ ./bin/str_substr_replace2 "This is ~my house~ bud" "~" "<b>" "</b>"
oldstr: This is ~my house~ bud
newstr: This is <b>my house</b> bud
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 access memory or write beyond/outside the bounds of your allocated block, 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/str_substr_replace2 "This is ~my house~ bud" "~" "<b>" "</b>"
==8962== Memcheck, a memory error detector
==8962== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8962== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==8962== Command: ./bin/str_substr_replace2 This\ is\ ~my\ house~\ bud ~ \<b\> \</b\>
==8962==
oldstr: This is ~my house~ bud
newstr: This is <b>my house</b> bud
==8962==
==8962== HEAP SUMMARY:
==8962== in use at exit: 0 bytes in 0 blocks
==8962== total heap usage: 1 allocs, 1 frees, 44 bytes allocated
==8962==
==8962== All heap blocks were freed -- no leaks are possible
==8962==
==8962== For counts of detected and suppressed errors, rerun with: -v
==8962== 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 further questions.