Hi I ran in to this situation. I am using malloc to give me an array of 10 pointers. When I see the test pointers in gdb, one of them(the third )points to 0x0. Sometimes the code segfaults when using apple[2]->string = "hello". Why does malloc do this? Thanks in advance for the help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
typedef struct test
{
char *string;
int data;
} test;
test *apple[10]; // Declare an array of 10 test pointers. This line results in one of the pointers having a null value.
apple[0] = malloc(sizeof(test));
apple[0]->string = "hello";
printf("The string is %s\n",apple[0]->string);
printf("Size of apple[0]->data is %d\n",sizeof(apple[0]->data));
printf("Size of tester is %d\n",sizeof(test));
free(apple[0]);
return 0;
}
I wanted to see how the array of pointers would work. I was not intending on using all the 10 pointers. So do I need to malloc only what I need? Is it a coincidence, that the third pointer was 0x0?
Memory has only been allocated for first element in apple so only apple[0] points to a valid struct test.
To allocate memory for all elements of apple:
for (int i = 0; i < sizeof(apple) / sizeof(test*); i++)
{
apple[i] = malloc(sizeof(test));
}
Similar loop required to free().
test.string is a char*, so pointing to a string literal as you have done is fine (though type should be const char*). If you wish to copy a string to test.string then you must malloc() space to copy into and free() it later.
There are different approaches, depending on what your final goal is.
If the number of elements in your array is meant to be constant every time the program is run, you don't have to use pointers at all:
test apple[10]; // array with 10 instances of test
test[0].string = ...;
test[1].data = ...;
If you'd like to use your approach (with pointers, which isn't really necessary right now), you have to malloc() every element on its own (like you did with apple[0], or malloc() the whole array:
int num = 10;
test *apple = malloc(sizeof(test) * num);
// access any element here
apple[5].string = "hello!";
free(apple);
You are allocating only one instance of the test and you're assigning it to the first array element:
apple[0] = malloc(sizeof(test));
To allocate all ten, you'd do:
for (int i = 0; i < 10; i++) {
apple[i] = malloc(sizeof(test));
}
Related
Recently I was pondering over this question: how to make an easier way to iterate over an array of pointer in C.
If I create an array of string in C, it should look like this right?
int size = 5;
char ** strArr = (char **) malloc(sizeof(char *) * size);
if (strArr == NULL) return;
But the problem is, when you want to iterate over this array for some reason (like printing all values inside it), you have to keep track of its current size, storing in another variable.
That's not a problem, but if you create lots of arrays, you have to keep track of every single one of their sizes inside the code. If you pass this array to another function, you must pass its size as well.
void PrintValues (char ** arr, int size) {
for (int i = 0; i < size; i++)
printf("%s\n", arr[i]);
}
But when iterating over a string, it's different. You have the '\0' character, which specifies the end of the string. So, you could iterate over a string like this, with not need to keep its size value:
char * str = (char *) malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
for (int i = 0; str[i] != '\0'; i++)
printf("%c", str[i]);
printf("\n");
Now my question:
Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
char ** strArr = (char **) malloc(sizeof(char *) * (5 +1);
if (strArr == NULL) return;
strArr[0] = PseudoFunc_NewString("Car");
strArr[1] = PseudoFunc_NewString("Car#1");
strArr[2] = PseudoFunc_NewString("Car#2");
strArr[3] = PseudoFunc_NewString("Tree");
strArr[4] = PseudoFunc_NewString("Tree#1");
strArr[5] = NULL; // Stop iteration here as next element is not allocated
Then I could use the NULL pointer to control the iterator:
void PrintValues (char ** arr) {
for (int i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
This would help me to keep the code cleaner, though it would consume more memory as a pointer size is larger than a integer size.
Also, when programming with event-based libraries, like Gtk, the size values would be released from the stack at some point, so I would have to create a pointer to dynamically store the size value for example.
In cases like this, it ok to do this? Or is it considered something bad?
Is this technique only used with char pointers because char type has a size of only 1 byte?
I miss having a foreach iterator in C...
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
This is ok, the final NULL is called a sentinel value and using one is somewhat common practice. This is most often used when you don't even know the size of the data for some reason.
It is however, not the best solution, because you have to iterate over all the data to find the size. Solutions that store the size separately are much faster. An arrays of structs for example, containing both size and data in the same place.
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
In C this is quite a common pattern, and it has a name. You're simply using a sentinel value.
As long as your list can not contain null pointers normally this is fine. It is a bit error-prone in general however, then again, that's C for you.
It's ok, and is a commonly used pattern.
As an alternative you can use a struct, in there you can create a size variable where you can store the current size of the array, and pass the struct as argument. The advantage is that you don't need to iterate through the entire array to know its size.
Example:
Live demo
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
char **strArr;
int size;
} MyStruct;
void PrintValues(MyStruct arr) //pass the struct as an argument
{
for (int i = 0; i < arr.size; i++) //use the size passed in the struct
printf("%s\n", arr.strArr[i]);
}
int main()
{
// using the variable to extract the size, to avoid silent errors
// also removed the cast for the same reason
char **strArr = malloc(sizeof *strArr * 5);
if (strArr == NULL) return EXIT_FAILURE;
strArr[0] = "Car";
strArr[1] = "Car#1";
strArr[2] = "Car#2";
strArr[3] = "Tree";
strArr[4] = "Tree#1";
MyStruct strt = { strArr, 5 }; // initialize the struct
PrintValues(strt); //voila
free(strArr); // don't forget to free the allacated memory
return EXIT_SUCCESS;
}
This allows for direct access to an index with error checking:
// here if the array index exists, it will be printed
// otherwise no, allows for O(1) access error free
if(arr.size > 6){
printf("%s\n", arr.strArr[6]);
}
I'm a student learning C and I was puttering around with arrays of strings and malloc().
I have the following code that is supposed to load an array of strings (statically created) with dynamically created strings (please forgive / correct me if my terminology does not align with the code I have).
The problem is, once I go to free that memory, I get the following error: free(): invalid pointer
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#define RAM_SIZE 5
char* ram [RAM_SIZE];
int next_free_cell = 0;
void freeAndNullRam(){
for (int i = 0 ; i < RAM_SIZE ; i++){
printf("%d\n", i);
free(ram[i]);
ram[i] = NULL;
}
}
int main(int argc, const char *argv[])
{
for (int i= 0; i < RAM_SIZE; i++){
ram[i] = (char*)malloc(sizeof(char*)*5);
ram[i] = "aaaa";
}
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
if(!empty){
printf("%s\n", ram[i]);
}
}
freeAndNullRam();
for (int i= 0; i < RAM_SIZE; i++){
int empty = (ram[i] ==NULL);
printf("%d\n", empty);
}
return 0;
}
I know the issue is definitely in the freeAndNullRam() function (obviously), but I don't understand why. My understanding is that at compile time, an array of 5 pointers to char arrays is created, but to actually fill the cells of the array, I need to malloc them some memory. Why does the program complain when I free the pointers in the array, but not when I give them memory?
Thanks!
ram[i] = "aaaa"; reassigns the pointers at a[i] to point to static memory, discarding the result of malloc. Later on you pass those pointers to free, which fails because they were not the result of an *alloc function.
Use strcpy to instead copy the string from static memory into your allocated destination.
strcpy(a[i], "aaaa")
Here's a reworked version of your code to be more idiomatic C:
#include <stdio.h>
#include <stdlib.h>
// Create an array of arbitrary size
char* alloc_array(size_t size) {
// calloc() will give you a pre-zeroed (NULL) allocation, malloc() may not
return calloc(size, sizeof(char*));
}
// Clears out all entries in the array, leaving only NULL
void clear_array(char* array, size_t size) {
for (size_t i = 0; i < size; ++i) {
// free(NULL) doesn't do anything, and is easier than a test
free(array[i]);
array[i] = NULL;
}
}
// Clears, then frees the array
void free_array(char* array, size_t size) {
clear_array(array, size);
free(array);
}
int main(int argc, const char *argv[])
{
// Whenever possible use local variables, not global variables
size_t size = 5;
char* entries = alloc_array(size);
for (size_t i = 0; i < size; ++i) {
// Make a copy with strdup() so this can be released with free()
// later on. A string like "..." is static, it was never allocated.
entries[i] = strdup("aaaa");
}
for (size_t i = 0; i < size; i++) {
// Express conditions in the if statment directly
if (entries[i] != NULL) {
printf("%s\n", ram[i]);
}
}
clear_array(entries);
for (size_t i = 0; i < size; i++) {
printf("%d\n", entries[i] != NULL);
}
// Don't forget to release any allocated memory.
free_array(entries);
return 0;
}
There's a lot of bad habits in your original code you should work to expunge as quickly as possible so these things don't take root. In particular, global variables are a huge problem that need to be avoided.
One thing to remember is unless something was explicitly allocated with malloc() or a variant like calloc(), or was given to your code with an understanding that it was allocated in such a fashion, you should not call free() on it.
Not every pointer was allocated dynamically, and not every dynamically allocated pointer was allocated with malloc(). Some C code can be very confusing as a result of this.
C's syntax strongly suggests that "aaaa" is a "string". People even talk of this syntax that way: they call it "strings". But "aaaa" is nothing such. It's the unfortunately named string literal, which is not a string - neither in C nor in C++. A char * is not a string either - it's a pointer-typed value. It's used to represent strings, but itself is not a string - not even close.
You have quite reasonably expected that "aaaa" might behave like any other rvalue of the "obvious" type. Alas, while 1 is an integer literal of type int, "aaaa" is a string literal of a pointer type const char * - its value is not a string, but a pointer!
It's as if when you wrote 42, C gave you a const int * pointing to 42. That's what "string" literals do. That's the awfully deplorable side of C :(
In C++, there actually is a string type (std::string), and you can even write literals of that type with a new syntax introduced in C++11: "aaaa"s is an rvalue* of type std::string, and you can assign them exactly as you would expect of any other value type like int.
Since you're already thinking a bit like in C++, perhaps you can investigate that language next. It takes much less effort to do plenty of basic things in C++ compared to C.
*technically rvalue reference
I'm pretty new to C and starting to play with pointers. I haven't found a way to assign an array to multiple variables.
What I want ideally is:
char myArray[10] = "test";
char (*p)[10] = &myArray;
char anotherArray[10];
anotherArray = *p;
This doesn't work and I don't know why.
I have found a way to "copy" the array by using a for loop,
for (int i = 0; i < 10; i++)
{
anotherArray[i] = myArray[i];
}
I don't know if it's good practice to do it and if there is an easier way.
The array content is not supposed to change so I just want to have a simple way to do this:
firstArr[size] = "content";
secondArr = firstArr;
You can't assign arrays in C, neither by itself nor by dereferencing pointers to arrays, the syntax simply doesn't allow it.
Arrays are normally copied with memcpy. In case they are strings, you can also use strcpy, which copies up until it finds the string null terminator.
In your example, this would be strcpy(anotherArray, *p);. But to use an array pointer of type char (*)[10] is a bit weird practice, it is far more common to use a pointer to the first element of the array. I would recommend that you change your code to this:
#include <stdio.h>
#include <string.h>
int main(void)
{
char input[10] = "test";
char* p = input;
char anotherArray[10];
strcpy(anotherArray, p);
puts(anotherArray);
}
You can't assign an array to multiple variables, but you can assign multiple variables to point to an array.
Pointers are all about memory and the memory that they point to.
Statements such as this assign a fixed amount of memory (10 char sized bytes of memory) to the variable myArray and initialises the contents to contain "test1".
char myArray[10] = "test1";
By definition myArray is actually a pointer to the first memory location, which in this case holds a char of value 't', but it is fixed to that memory.
You can define another pointer to type char and assign it the same value as the pointer to the memory that holds the data "test1" - thus:
char *secondPtr = myArray;
Now secondPtr and myArray both point to the same memory, which contains "test1". There aren't two copies of the data, but it may appear so if you did
printf("myArray %s", myArray);
printf("secondPtr %s", secondPtr);
Now you can use either myArray or secondPtr to alter the same data, which is why pointers should be treated with care.
Now as secondPtr is just a pointer to a char and as such it isn't fixed in the same way that myArray is, so you can do this:
char myArray2[10] = "test2";
secondPtr = myArray;
printf("secondPtr %s", secondPtr);
secondPtr = myArray2;
printf("secondPtr %s", secondPtr);
To copy data from one array to another you can use memcpy, which will copy a specified number of bytes(octets) of memory from one location to another.
The same process is performed by a loop (this is basic code, but not really the best way of performing it as there are no checks on the size of the arrays nor on the number of loop iterations)e.g.
for(int i=0; i<10; i++)
{
myArray2[i] = myArray[i];
}
this can also be:
secondPtr = myArray2;
for(int i=0; i<10; i++)
{
myArray2[i] = secondPtr +i;
}
I have a function which creates an array, of say, size 5.
Is it possible for the function to accept a pointer (or maybe it needs a pointer to a pointer?) and then point said pointer at an array, so that when the callee then looks at the pointer, it can see all values of the array.
Something along the lines of this (except this will not work):
#define LENGTH 5
void assignArray(int *pointer)
{
int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
pointer = arr;
}
void main()
{
int *pointer;
pointer = malloc(sizeof(int) * LENGTH);
assignArray(pointer);
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer[i]);
}
C assign array without element by element copy
In C, arrays (compile-time allocated) cannot be assigned. You need to copy the elements from one array to another.
To avoid element-by-element copy, you can copy the whole array all at a time using library function.
I'm not very sure what you want to ask here, but it seems, you need to do memcpy() to achieve your goal.
If you have a secondary array arr to copy from, you can write
memcpy( pointer, arr, ( (sizeof arr[0]) * LENGTH ));
The code to do what you are describing might look like:
#define LENGTH 5
void assignArray(int **pp)
{
static int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
*pp = arr;
}
int main()
{
int *pointer;
assignArray(&pointer);
for (int i = 0 ; i < LENGTH ; i++)
printf("%d\n", pointer[i]);
}
Note that one does not simply point *pp at a non-static local variable arr. That is because int arr[] = .... would go out of scope when assignArray returns.
If you want each call to assignArray to "return" a different array then of course you will have to allocate space and use memcpy each time you want to make a copy of the original array.
int arr[LENGTH] = {0,1,2,3,4}; will be stack allocated, so attempting to return the pointer to any of its elements will give you undefined behaviour as the whole thing will be out of scope when the function returns.
If you want to change what a pointer is pointing to then use 2 levels of indirection ** (i.e. pass a pointer to a pointer). You'll need to allocate the array arr on the heap using malloc or something similar.
As you are trying to do it, it is not possible due to the fact that your local arr is saved to the stack and is cleaned up after the function assignArry finished. As already mentioned you need to memcpy.
This answer will have two parts:
As mentioned in other answers, this is now how you're supposed to do it. A common construct in similar code is:
void assignArray(int *dest, size_t size)
{
int i;
// initialize with some data
for (i=0; i<size; i++)
dest[i] = i;
}
This way you're not wasting space and time with an intermediate buffer.
Second part of this answer is about wrapping arrays in a struct. It's a silly trick, that in a way achieves exactly what you asked, and also something that you probably don't want because of extra data copying.
Example code:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 5
struct foo { int arr[LENGTH]; };
struct foo assignArray()
{
struct foo bar = { .arr = {0,1,2,3,4} };
/* return the array wrapper in struct on stack */
return bar;
}
int main()
{
struct foo *pointer;
pointer = malloc(sizeof(*pointer));
*pointer = assignArray(); /* this will copy the data, not adjust pointer location */
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer->arr[i]);
return 0;
}
I am working on an assignment and ran into challenging problem. As far as I'm concerned and from what I've learnt the code that follows should be correct however it does not work. Basically what I am trying to is copy a string value into the variable member of a structure the is part of an array passed into a method as a pointer. What am I missing?
typedef struct
{
char * name; //variable in struct I am trying to access
} Struct;
void foo(Struct * arr) //array of Structs passed into function as a pointer
{
int i = 0;
while(i++ < 2)
{
arr[i].name = malloc(sizeof(char *)); //assigning memory to variable in each Struct
arr[i].name = strdup("name"); //copying "name" to variable in each Struct
printf("C - %s\n", arr[i].name); //printing out name variable in each Struct
}
}
main()
{
Struct * arr; //defining pointer
arr = calloc(2, sizeof(Struct)); //allocating memory so pointer can hold 2 Structs
foo(arr); //calling function foo passing pointer into function
return 0;
}
This code compiles and runs however it does not do what it is designed to do. Forgive me if it is something trivial. I am new to the language C
Two issues:
while(i++ < 2) This line changes the value of i as soon as it checks it, so your loop body will not be the same as it was checked.
arr[i].name = strdup("name"); overwrites the value of the .name pointer, causing a memory leak of the memory you malloc()'ed earlier.
Extending on 2 pointed out correctly already,
arr[i].name = strdup("name");
Even if you use following instead of above,
strcpy(array[i].name, "name");
you haven't allocated enough bytes to store the string i.e. this is wrong
arr[i].name = malloc(sizeof(char *));
// even if pointer is 8 byte here, concept isn't right
Should be something like
arr[i].name = malloc(strlen("name")+1);
// or MAX_SIZE where it is greater than the possible "name".
Or better yet, remove the malloc at all, strdup takes care of allocation itself
This is not answering your question directly, but addresses an issue to big to put into a comment...
Additional issue: You probably did not intend to allocate only a (char *) worth of memory to a variable intended to hold at least "name". Change;
arr[i].name = malloc(sizeof(char *));
to:
arr[i].name = malloc(sizeof(char)*strlen("name")+1); //+1 for '\0'
or better yet, use char *name="name";, then:
arr[i].name = malloc(sizeof(char)*strlen(name)+1);
Even more general (and better):
char *name;
name = malloc(strlen(someInputString)+1);
//do stuff with name...
free(name);
Now, you can allocate name to any length needed based on the length of someInputString.
[EDIT]
Etienz, I wanted to address one more thing, alluded to by #H2CO3 above, but not really explained, that I think might be useful to you:
Regarding your desire to have room for two structs, because you typedef'd your struct, you can simply do something like this: (but I am going to change the name you used from Struct to NAME :) The whole point being that when a struct is created as an array, you do not need to use calloc or malloc to create space for them, it is done as shown below...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char *name;
}NAME;
//use new variable type NAME to create global variables:
NAME n[2], *pN; //2 copies AND pointer created here
//prototype func
int func(NAME *a);
int main()
{
pN = &n[0]; //pointer initialized here
func(pN); //pointer used here (no malloc or calloc)
printf("name1 is %s\nname 2 is %s", pN[0].name, pN[1].name);
return 0;
}
int func(NAME *a)
{
char namme1[]="andrew";
char namme2[]="billebong";
//You DO have to allocate the members though
a[0].name = malloc(strlen(namme1)+1);
a[1].name = malloc(strlen(namme2)+1);
strcpy(a[0].name, namme1);
strcpy(a[1].name, namme2);
return 0;
}