How to copy the values of an array of char pointers? - c

How do I copy the values in an array of char pointers into another array? I am really lost please help me out. This is what I have so far.
char **copy_values(char **values) {
char **val;
//do something
return val;
}

To fully copy the pointers and values (what they point to), you need to know three things:
How many pointers do I have?
Do I need to also copy the things they point to?; and if so
How many pointers do I have that point to something I need to copy.
When you declare a pointer to pointer to char, it is simply an uninitialized pointer. To provide the ability to address more than a single address, you then allocate some needed number of pointers (say MAXPTRS). For instance:
#define MAXPTRS 32
...
char **values = NULL;
values = malloc (MAXPTRS * sizeof *values); /* allocate MAXPTRS pointers */
if (values == NULL) { /* validate/handle error */
perror ("malloc-values");
/* handle error */
}
You now have MAXPTRS (32) pointers to work with. If you then allocate storage for say 8 of them, e.g.
size_t count = 0;
while (fgets (buf, sizeof buf, stdin)) {
size_t len = strlen (buf);
values[count] = malloc (len + 1);
if (!values[count]) {
perror ("malloc-values[count]");
break;
}
memcpy (values[count++], buf, len + 1);
}
So at this point in the example, you have 32 pointers allocated and 8 of those pointers pointing to blocks of memory holding strings read from stdin.
If you then want to copy the entire structure, you must not only copy the original 32 pointers, but also the 8 blocks of memory the initialized pointers point to. If you fail to copy the blocks of memory pointed to and simply assign pointers (e.g. val[i] = values[i]), then any changes to the original, e.g. values[2] will automatically be reflected in val[2] (this may, or may not, be what you want)
To fully copy your values pointer to pointer to char and return val containing the same number of pointers with a copy of each string allocated and contained in the original values array of pointers, you would need a "deep copy" where you copy not only the pointers, but duplicate the contents as well, e.g.
char **copystrings (const char **values, size_t nptrs, size_t filled)
{
char **val = NULL;
val = malloc (nptrs * sizeof *val); /* allocate nptrs pointers */
if (!val) { /* validate */
perror ("malloc-val");
return NULL;
}
for (size_t i = 0; i < filled; i++) { /* loop over each filled ptr */
size_t len = strlen (values[i]); /* get length of string */
val[i] = malloc (len + 1) /* allocate storare val[i] */
if (!val[i]) { /* validate */
perror ("malloc-val[i]");
break;
}
memcpy (val[i], values[i], len + 1); /* copy to val[i] */
}
return val; /* return val (may contain less than filled allocated) */
}
(note: not compiled, also it would be advisable to pass filled as a pointer and update filled with the value of i before returning to provide a means of validating that all blocks of memory for filled pointers were duplicated. Otherwise, a malloc failure of val[i] would result in less than filled being allocated and copied and no way to tell -- unless you used calloc to zero the new memory when you allocate for val)
A deep copy allows you to modify the copied values without altering the data at the addresses pointed to by the pointers in values. If you are not modifying the data (e.g. you simply want to sort the pointers with qsort, then there is no need for a "deep copy" and you need only allocate for the filled number of pointers and assign the address from values to val.
Understanding what you need and the differences in how you go about achieving it is key.
(thanks to #4386427 for catching a couple of omissions)

How do I copy the values in an array of char pointers into another array?
Something like:
char **copy_values(char **values, int size) {
char **val = malloc(size * sizeof *val);
if (val) memcpy(val, values, size * sizeof *val);
return val;
}
Remember to free the allocated memory when done with it

Related

Differences between allocating memory spaces for a string based on the size of its characters vs. the size of the entire string

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)

How do I use char** ? (pointer to an array of chars)

So I'm trying to make a char**, I fully understand how it works in the background and all that stuff but I don't seem to understand how to write the code for it. I want to make a pointer to an array of chars which has a name in it. I need help with storing a string in it (using strcpy() ) and print it after that.
char** name = (char**)malloc((strlen("MyName") + 1) * sizeof(char*));
strcpy(name, "MyName"); // I get an error right here
If you really want a pointer to an char array, you could do the following:
char** name = (char**)malloc(sizeof(char*)); //initialize the pointer
*name = (char*)malloc((strlen("MyName") + 1) * sizeof(char)); //initialize the array
strcpy(*name, "MyName");
So I'm trying to make a char**, I fully understand how it works in the
background and all that stuff but I don't seem to understand how to
write the code for it.
Umm... No, not quite.
To declare a pointer-to-char, you simply decalre:
char *name = malloc (strlen("MyName") + 1);
Why? When you make your call to malloc, malloc allocates a block of memory providing strlen("MyName") + 1 bytes and returns the starting address to that block of memory -- which you assign to name. You then can copy "MyName" to name (with 1-byte remaining for the nul-terminating character). The approach would be:
size_t len = strlen ("MyName");
char *name = malloc (len + 1); /* allocate len + 1 bytes */
if (name == NULL) { /* validate EVERY allocation */
perror ("malloc-name");
/* handle error by returning or exiting */
}
memcpy (name, "MyName", len + 1); /* no need to scan again for \0 */
/* do something with name - here */
free (name); /* don't forget to free name when you are done */
What then does char** do?
When you are dealing with a pointer-to-pointer-to-char, you must first allocate for some number of pointers, then you can allocate and assign a block of memory to each of the pointers and use each pointer just as you have used name above.
For example:
/* array of ponters to string-literals for your source of strings */
char *band[] = { "George", "Ringo", "Paul", "John" };
char **names;
size_t nmembers = sizeof band / sizeof *band;
/* allocate nmembers pointers */
names = malloc (nmembers * sizeof *names);
if (names == NULL) { /* validate EVERY allocation */
perror ("malloc-name_pointers");
/* handle error by returning or exiting */
}
/* now loop allocating for each name and copy */
for (size_t i = 0; i < nmembers; i++) {
size_t len = strlen (band[i]); /* get length */
names[i] = malloc (len + 1); /* allocate */
if (names[i] == NULL) { /* validate EVERY allocation */
perror ("malloc-names[i]");
/* handle error by returning or exiting */
}
memcpy (names[i], band[i], len + 1);/* no need to scan again for \0 */
}
/* output each */
for (size_t i = 0; i < nmembers; i++)
printf ("member[%zu]: %s\n", i + 1, names[i]);
Freeing names is a two step process. You must free the memory allocated to each of the names pointers and then free the pointers themselves, e.g.
for (size_t i = 0; i < nmembers; i++)
free (names[i]); /* free each allocated names[i] */
free (names); /* free pointers */
Now hopefully you more closely "... fully understand how it works". Let me know if you have any questions.
First thing you should understand is that declaring a variable as a single pointer or a double pointer (or any other n pointer) doesn't actually tell whether the underlying variable holds a single value or an array of values.
Single pointer points to a memory address on which actual value is stored. Double pointer points to a memory address on which single pointer is stored, and so on.
Now, to make a pointer to an array of char pointers you can use a single char pointer (char*) but I recommend to use double char pointer (char**) for maintainability purposes.
Consider the following code:
char** names = (char**)malloc(100 * sizeof(char*));
It will allocate memory space for 100 char pointers (char*) on heap and return you a double pointer (char**) to the first single pointer (char*) in that memory space. This means you will be able to save 100 char pointers (or 100 names in your case) inside that memory space. Then you can use them like this:
char* name0 = "First Name"; // Saved on stack
char* name1 = malloc((strlen("Second Name") + 1) * sizeof(char)); // Saved on heap
strcpy(name1, "Second Name");
names[0] = name0;
names[1] = name1;
Also, please note that when saving a string on heap you need to add one more place for null character (manually).

How to dynamically allocate memory in an array of strings for some new string and copy that string into the dynamically allocated space in C?

Here is the code that I have:
void InsertStringAt(char *array[], char *s, int pos)
{
if (pos<array.size())
{
*array[pos]=(s *)malloc(sizeof(s));
strcopy(*array[pos], *s);
}
else printf("Position exceeds dimensions of array.");
}
The purpose of this function is to insert the string s into position pos of array[]. Will this code accomplish that?
No, this won't do it:
first you cast the result of malloc to (s *) but s is not a type (it is a variable). Then you allocate room the size of s but s is a pointer, so you allocate only room for a pointer.
Then array is declared as an array of pointers to characters. Now you don't need to dereference array anymore when you access a member. The compiler will do that and if you do that, then there is one dereferencing too many.
Do:
array[pos]= malloc(strlen(s)+1);
Lastly, in C there are no classes so array.size is invalid. You must pass the array size as a separate variable.
May I suggest you return an int to indicate everything was successful? E.g. no out-of-memory and pos < size?
sizeof a pointer simply gives you 8 or 4 (depending on your word size). So to get the length of a string, use strlen() from <string.h>. Also, you needn't cast the return value from malloc. So you'd get:
array[pos] = malloc(strlen(s)+1);
Notice that the dereferencing was removed, since it's already dereferenced.
Also, the function is strcpy() not strcopy(). strcpy() is declared in <string.h>. But strcpy() may lead to buffer overflows, consider making your own:
int safecpy(char *s, const char *t, size_t siz)
{
size_t i;
for (i = 1; (*s = *t) && i < siz; ++i, s++, t++)
;
s[i] = 0; /* null terminate the string */
return i;
}
C arrays do not know their own size; So pass it as a separate argument. It is recommended that sizes are represented with size_t and not int.
Finally, print error messages to stderr, so they don't get pipelined into another program or redirected into a file:
else fprintf(stderr, "Position exceeds dimensions of array.");

Freeing memory in the caller that is reallocated by the callee?

Here is my situation:
main allocates memory based on string and calls function by passing an address. The function then appropriately resizes the passed memory to accommodate more data. After which when I try to release the memory I get heap error.
Here is the code:
typedef char * string;
typedef string * stringRef;
/**************************
main
**************************/
int main()
{
string input = "Mary had";
string decoded_output = (string)calloc(strlen(input), sizeof(char));
sprintf(decoded_output, "%s", input);
gen_binary_string(input, &decoded_output);
free(decoded_output); /*this causes issue*/
return 0;
}
void gen_binary_string(string input,stringRef output)
{
int i=0, t=0;
size_t max_chars = strlen(input);
/*
the array has to hold total_chars * 8bits/char.
e.g. if input is Mary => array size 4*8=32 + 1 (+1 for \0)
*/
string binary_string = (string)calloc((BINARY_MAX*max_chars) + 1, sizeof(char));
int offset = 0;
/* for each character in input string */
while (*(input+i))
{
/* do some binary stuff... */
}
/* null terminator */
binary_string[BINARY_MAX*max_chars] = '\0';
int newLen = strlen(binary_string);
string new_output = (string) realloc((*output), newLen);
if (new_output == NULL)
{
printf("FATAL: error in realloc!\n");
free(binary_string);
return;
}
strcpy(new_output, binary_string);
(*output) = new_output;
free(binary_string);
}
You may be misunderstanding the purpose of realloc. Calling realloc will not necessarily return a newly allocated object. If possible, it will return the same object, extended to hold more bytes. Also, it automatically copies the object's contents. Theferore: (1) you should not copy and (2) you should not free the old buffer.
The realloc() function changes the size of the memory block pointed
to by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes... (snip) Unless ptr is NULL, it must have been returned by an
earlier call to malloc(), calloc() or realloc(). If the area
pointed to was moved, a free(ptr) is done.
After a better reading of your code, I don't understand why you're using realloc at all here, as you're not using the old contents of output. You'd get the same behaviour (and the same error) if you replaced realloc with malloc. I think your real problem is that you're not allocating enough bytes: you should have strlen(binary_string) + 1 to accommodate the '\0' at the end of the string.
A better option would be to pass in a char** from the caller, let the callee allocate the char* and then pass back the pointer at the end of the function.
This prevents the need for two allocations and one free (always a bad sign).

What does memcpy do exactly in this program?

I am writing a program where the input will be taken from stdin. The first input will be an integer which says the number of strings to be read from stdin.
I just read the string character-by-character into a dynamically allocated memory and displays it once the string ends.
But when the string is larger than allocated size, I am reallocating the memory using realloc. But even if I use memcpy, the program works. Is it undefined behavior to not use memcpy? But the example Using Realloc in C does not use memcpy. So which one is the correct way to do it? And is my program shown below correct?
/* ss.c
* Gets number of input strings to be read from the stdin and displays them.
* Realloc dynamically allocated memory to get strings from stdin depending on
* the string length.
*/
#include <stdio.h>
#include <stdlib.h>
int display_mem_alloc_error();
enum {
CHUNK_SIZE = 31,
};
int display_mem_alloc_error() {
fprintf(stderr, "\nError allocating memory");
exit(1);
}
int main(int argc, char **argv) {
int numStr; //number of input strings
int curSize = CHUNK_SIZE; //currently allocated chunk size
int i = 0; //counter
int len = 0; //length of the current string
int c; //will contain a character
char *str = NULL; //will contain the input string
char *str_cp = NULL; //will point to str
char *str_tmp = NULL; //used for realloc
str = malloc(sizeof(*str) * CHUNK_SIZE);
if (str == NULL) {
display_mem_alloc_error();
}
str_cp = str; //store the reference to the allocated memory
scanf("%d\n", &numStr); //get the number of input strings
while (i != numStr) {
if (i >= 1) { //reset
str = str_cp;
len = 0;
}
c = getchar();
while (c != '\n' && c != '\r') {
*str = (char *) c;
printf("\nlen: %d -> *str: %c", len, *str);
str = str + 1;
len = len + 1;
*str = '\0';
c = getchar();
if (curSize/len == 1) {
curSize = curSize + CHUNK_SIZE;
str_tmp = realloc(str_cp, sizeof(*str_cp) * curSize);
if (str_tmp == NULL) {
display_mem_alloc_error();
}
memcpy(str_tmp, str_cp, curSize); // NB: seems to work without memcpy
printf("\nstr_tmp: %d", str_tmp);
printf("\nstr: %d", str);
printf("\nstr_cp: %d\n", str_cp);
}
}
i = i + 1;
printf("\nEntered string: %s\n", str_cp);
}
return 0;
}
/* -----------------
//input-output
gcc -o ss ss.c
./ss < in.txt
// in.txt
1
abcdefghijklmnopqrstuvwxyzabcdefghij
// output
// [..snip..]
Entered string:
abcdefghijklmnopqrstuvwxyzabcdefghij
-------------------- */
Thanks.
Your program is not quite correct. You need to remove the call to memcpy to avoid an occasional, hard to diagnose bug.
From the realloc man page
The realloc() function changes the size of the memory block pointed to
by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes
So, you don't need to call memcpy after realloc. In fact, doing so is wrong because your previous heap cell may have been freed inside the realloc call. If it was freed, it now points to memory with unpredictable content.
C11 standard (PDF), section 7.22.3.4 paragraph 2:
The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.
So in short, the memcpy is unnecessary and indeed wrong. Wrong for two reasons:
If realloc has freed your previous memory, then you are accessing memory that is not yours.
If realloc has just enlarged your previous memory, you are giving memcpy two pointers that point to the same area. memcpy has a restrict qualifier on both its input pointers which means it is undefined behavior if they point to the same object. (Side note: memmove doesn't have this restriction)
Realloc enlarge the memory size where reserved for your string. If it is possible to enlarge it without moving the datas, those will stay in place. If it cannot, it malloc a lager memory plage, and memcpy itself the data contained in the previous memory plage.
In short, it is normal that you dont have to call memcpy after realloc.
From the man page:
The realloc() function tries to change the size of the allocation pointed
to by ptr to size, and returns ptr. If there is not enough room to
enlarge the memory allocation pointed to by ptr, realloc() creates a new
allocation, copies as much of the old data pointed to by ptr as will fit
to the new allocation, frees the old allocation, and returns a pointer to
the allocated memory. If ptr is NULL, realloc() is identical to a call
to malloc() for size bytes. If size is zero and ptr is not NULL, a new,
minimum sized object is allocated and the original object is freed. When
extending a region allocated with calloc(3), realloc(3) does not guaran-
tee that the additional memory is also zero-filled.

Resources