This question already has answers here:
String assignment in C
(4 answers)
Closed 7 years ago.
Here's the snippet with issues.
int main()
{
char** RESERV = (char**)malloc(sizeof(char*)*4);
printf("%i, %i, %i, %i, %i", **RESERV, *RESERV, RESERV, &**RESERV, sizeof(char*));
int i;
for(i = 0; i < 4; i++)
{
RESERV[i] = (char*)calloc(sizeof(char),16);
RESERV[i][15] = '\0';
}
for(i = 0; i < 4; i++)
RESERV[i]="Iambananananananananananana";
for(i = 0; i < 4; i++)
printf("\r\n>%i<", RESERV[i]);
for(i = 0; i < 4; i++)
{
printf("\r\n<%i>", (RESERV[i]));
free(RESERV[i]);
}
free(RESERV);
}
This code free() is working fine in 32 bit , but somehow crashes horribly in 64 bit mode.
In my main program I've omitted freeing the members of the char** causing unexptected behavior every now and then, which I obviously do not want.
I've tried playing around with addresses and pointers, even tried
free(RESERV+(i*sizeof(char*))
Which failed too. Can someone clarify what I'm doing wrong?
In your code
RESERV[i]="Iambananananananananananana";
creates the problem. It overwrites the memory allocated by malloc(). Thus,
You face memory leak, because the malloc()ed pointer is lost.
You cannot call free() with the changed pointer. It invokes undefined behaviour.
Solution:
In C, you don't assign strings, instead, you can use strcpy() to get your work done.
Notes:
even in case of strcpy() you cannot use "Iambananananananananananana". In this case, it will create memory overrun as destination does not have enough memory to hold it completely.
Use proper format specifiers. in your printf() statements, most of the arguments to %i are not of type int. For pointer type arguments, you should be using %p, atleast. Otherwise, it will be UB.
RESERV[i]="Iambananananananananananana";
This is not the proper way to populate this string after allocating it. You are overwriting the value of that pointer.
strncpy(RESERV[i], "Iambananananananananananana", 15);
RESERV[i][15] = 0;
This is what you're looking for.
Notice, too, that you are apparently to assign something into that pointer that is larger than the memory that you have allocated.
The line
RESERV[i]="Iambananananananananananana";
is incorrect - You need to do
strncpy(RESERV[i], "Iambananananananananananana", 15);
RESERVp[i][15] = 0;
Related
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
This is a small piece of code that I made while trying to understand how malloc and pointers work.
#include <stdio.h>
#include <stdlib.h>
int *buffer (int count)
{
int *buffer = malloc (count * sizeof(int));
for (int i = 0; 0 <= i && i < count; i++)
{
buffer[i] = 0;
}
return &buffer;
}
int main ()
{
int size = 0;
int i = 0;
scanf ("%d", &size);
int *num = buffer (size);
while (i < size)
{
scanf ("%d", &num[i]);
i++;
}
}
For some reason that I can't understand, I keep getting a segmentation fault. This error repeatedly happens on the last scanf() and I do not know why. I know i have to pass pointer to scan f and num is already a pointer so i thought that i would not need to include the &. But, I received a segmentation fault earlier if i do not. Also, I believe I have allocated the correct amount of space using malloc but I am not sure. Any help with what is happening here would be appreciated.
You returned the pointer to the local variable buffer, which will banish on exiting the function buffer.
You should remove the & used in the return statement and return the pointer to allocated buffer.
Also checking whether malloc() is successful should be added.
There are a couple of issues that I can see, and one of them is definitely a problem.
In function, int *buffer (int count)
return &buffer;
This will return address of buffer which is already a local int * variable.
So when the return happens, variable buffer would no longer be valid. Hence, the address is invalid.
One of the ways to go ahead as of now would be avoiding a function call buffer and using calloc().
Because, subject to availability, calloc() will allocate the memory of requested length, which will be initialized to 0 by default.
Or, the other way would be making the buffer pointer a global variable.
Also, with existing implementation, there needs a piece of code which checks if malloc returned anything or not. That would indicate if the memory was allocated or not.
Something like this would do:
int *buffer = malloc (count * sizeof(int));
if(buffer == NULL)
{
// Some error handling
return 0;
}
Additionally, I see the for loop which looks a bit weird than what it should look like:
for (int i = 0; 0 <= i && i < count; i++)
I take that you are trying to loop the count times and fill a 0 in buffer. This could have been achieved by
for (int i = 0; i < count; i++)
So, a malloc() is followed by en error-check and then followed by a for to fill the allocated memory with zeroes. So, using calloc makes life a lot easier.
Importantly, you allocate memory but you don't seem to have a code that de-allocates (frees) it. There are ample of examples to refer for doing that. I would recommend you to read concepts like Memory Leakage, Dangling Pointers and using valgrind or similar thing to validate the memory usage.
As a side-note and not a rule of thumb, always make sure that the names you use for variables are different than the names you use with functions. That creates a hell a lot of confusion. Going ahead with existing naming habit, you'll have a tough day when the code is reviewed.
This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 5 years ago.
I have written the following code:
#include <stdio.h>
#include <stdlib.h>
typedef struct _NeuralNetwork{
int input_rows;
int input_columns;
double **inputs;
}NeuralNetwork;
void main(){
// structure variable
NeuralNetwork *nn;
int count;
int i,j;
nn->input_rows = 2;
nn->input_columns = 3;
// create the array of double pointers using # of rows
nn->inputs = (double **)malloc(nn->input_rows * sizeof(double *));
// each pointer gets an array of double values
for (i=0; i<nn->input_rows; i++){
nn->inputs[i] = (double *)malloc(nn->input_columns * sizeof(double));
}
// assign values
count = 0;
for (i = 0; i < nn->input_rows ; i++)
for (j = 0; j < nn->input_columns; j++)
nn->inputs[i][j] = ++count;
// print those values
for (i = 0; i<nn->input_rows; i++)
for (j = 0; j < nn->input_columns; j++)
printf("%f ", nn->inputs[i][j]);
/* Code for further processing and free the
dynamically allocated memory*/
return;
}
When I compile this everything is okay. But after running it, I get a segmentation fault error:
Segmentation fault (core dumped)
I am not sure, where the mistake is. Can somebody help?
Note: When I use nn as structure variable instead of a structure, then everything is fine. But I want to use it as structure pointer and access the structure members via "->" and not via "." since I plan to pass nn as pointer to another function later.
Thank you in advance :)
The variable nn is a pointer, but that pointer is never initialized. You subsequently read and dereference that pointer using an operation such as nn->input_rows = 2;. This invokes undefined behavior.
In this particular case, nn likely contains some garbage value. By dereferencing that pointer value, you are attempting to read from memory you probably aren't allowed to. This is what causes the crash.
By defining nn as an instance of a struct instead of a pointer, as you said you tried, you avoid this issue. You can still however pass a pointer to other functions by taking the address of this variable and passing that to the function, i.e.:
NeuralNetwork nn;
...
myfunction(&nn)
First, do not use void main(), it's non-standard and would eventually cause problems. The right way is int main() or int main(int argc, char** argv). Remember to return a proper value at the end of the main function, possibly 0. Consult the reference here: main function
Second, if you use NeuralNetwork *nn; you must allocate some space for it in memory. It's a pointer to some memory address, if you don't allocate it who knows where it points. That's why you're getting the segfault. You must allocate memory for it in the following way:
NeuralNetwork *nn = malloc(sizeof(NeuralNetwork));
Then it should work properly.
Here is the code I'm using:
#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
int i;
for (i = 0; i < sz; ++i) {
if (arr[i] != 0) {
printf("OK\n");
break;
}
}
free(arr);
return 0;
}
The program doesn't print OK. malloc isn't supposed to initialize the allocated memory to zero. Why is this happening?
malloc isn't supposed to initialize the allocated memory to zero. Why is this happening?
This is how it was designed more than 40 years ago.
But, at the same time, the calloc() function was created that initializes the allocated memory to zero and it's the recommended way to allocate memory for arrays.
The line:
arr = (int *)malloc(sz * sizeof(int));
Should read:
arr = calloc(sz, sizeof(int));
If you are learning C from an old book it teaches you to always cast the value returned by malloc() or calloc() (a void *) to the type of the variable you assign the value to (int * in your case). This is obsolete, if the value returned by malloc() or calloc() is directly assigned to a variable, the modern versions of C do not need that cast any more.
The man page of malloc says:
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that can
later be successfully passed to free().
So malloc() returns uninitialized memory, the contents of which is indeterminate.
if (arr[i] != 0)
In your program, You have tried to access the content of a memory block, which is invoked undefined behavior.
malloc isn't supposed to initialize the allocated memory to zero.
Memory allocated by malloc is uninitialised. Value at these locations are indeterminate. In this case accessing that memory can result in an undefined behavior if the value at that location is to be trap representation for the type.
n1570-ยง6.2.6.1 (p5):
Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. [...]
and footnote says:
Thus, an automatic variable can be initialized to a trap representation without causing undefined behavior, but the value of the variable cannot be used until a proper value is stored in it.
Nothing good can be expected if the behavior is undefined. You may or may not get expected result.
From the C Standard 7.22.3.4:
Synopsis
#include <stdlib.h>
void *malloc(size_t size);
Description
The malloc function allocates space for an object whose size is
specified by size and whose value is indeterminate.
The value is indeterminate. So, every compiler is free to behave how it wants. For example, in Microsoft Visual C++, in Debug mode, the area of allocated memory by malloc() is all set to 0xCDCDCDCD and when in Release mode it is random. In modern versions of GCC, it is set to 0x000000 if you don't enable code optimizations, and random otherwise. I don't know about other compilers, but you get the idea.
void *malloc(size_t size) is just supposed to keep aside the specified amount of space. That's all. There is no guarantee as to what will be present in that space.
Quoted from the man pages:
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that can
later be successfully passed to free().
Apart from calloc() you can use the memset() function to zero out a block of memory.
The first time you call malloc(3), it asks to the operating system to get memory for the heap space.
For security reasons, the unix/linux kernel (and many other operating systems) in general zeroes the page contents that is to be given to a process, so no process can access that memory's previous contents and do nasty things with it (like searching for old passwords, or similar things).
If you do several allocations and deallocations of memory, when the malloc module reuses the previous memory, you'll see garbage coming from malloc(3).
Zero's are assigned to page contents at first time in linux kernel.
Below program explains the memory initialisation difference in malloc and calloc:
#include<stdio.h>
#include<stdlib.h>
#define SIZE 5
int main(void) {
int *mal = (int*)malloc(SIZE*sizeof(int));
int *cal = (int*)calloc(SIZE, sizeof(int));
mal[4] = cal[4] = 100;
free(mal); free(cal);
mal = (int*)malloc(SIZE*sizeof(int));
cal = (int*)calloc(SIZE, sizeof(int));
for(int i=0; i<SIZE; i++) {
printf("mall[%d] = %d\n", i, mal[i]);
}
for(int i=0; i<SIZE; i++) {
printf("call[%d] = %d\n", i, cal[i]);
}
}
I use malloc to allocate everything from the heap(dynamic memory) while i should use calloc instead nowaday , and memset is great for filling you memory segment with any chosen character.
Compile and work great with GCC:
#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
int main()
{
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
memset(arr, 0, sz*sizeof(int) );
int i;
for (i = 0; i < sz; ++i) {
if (arr[i] != 0) {
printf("OK\n");
break;
}
}
free(arr);
return 0;
}
ref: http://www.cplusplus.com/reference/cstring/memset/
well, the value is not initialized in malloc.
And it does print "OK" in VS Code.
so in VS Code, the output is : "OK" followed by a garbage value.
in a web based compiler (here's the link : https://www.programiz.com/c-programming/online-compiler/ ),
the output was
"LOL" followed by '0'
so some compilers do initialize the value..but actually the value in malloc is not intialized. so it will return a garbage value when printed as in the above example in VS Code.
int main()
{
int *arr;
int sz = 100000;
arr = (int *)malloc(sz * sizeof(int));
int i;
for (i = 0; i < sz; i++)
{
if (arr[i] != 0)
{
printf("OK\n");
break;
}
else
{
printf("LOL \n");
break;
}
}
printf("%d", arr[0]);
free(arr);
My problem is that i am not sure how to allocate memory properly. I have researched it but to no avail. Some help regarding malloc would be great.
int main(int argc, char *argv[]) {
int i, a[5000], c = 1, m, n, input;
scanf("%d", &input);
for (i = 0; i <= 9999; i += 2) {
a[c] = i;
c++;
}
for (n = 2; n < 1118; n++) {
for (m = a[n]; m < a[5000]; m++) {
a[m] = a[m+1];
}
}
printf("%d", a[input]);
free (*a);
return 0;
}
'a' is allocated on stack therefore no need to free it.
You only need to free variables allocated by *alloc family of functions.
First of all, C arrays have 0-based indexing. By setting the intial value of c to 1 and then using as index inside the loop, you're going off-by-one. This invokes undefined behavior.
After that, you don't need to do free (*a);, a is an array, not a pointer returned by a memory allocator functions, malloc() or family.
That said, in this code, *a does not give you a pointer, at all, it is same as a[0] which is of type int.
Finally, without any bound checking from user supplied value of input, using a[input] may very well be accessing out of bound memory, causing UB.
FWIW, passing a pointer to free() which is not returned previously by malloc() and family also invokes undefined behavior.
malloc takes one argument - the number of bytes to allocate. It returns a void pointer (which is a pointer to a section of memory that can hold any data type).
Here's an example.
int *array = malloc(sizeof(int) * 10);
This allocates a 10-element array of integers. Note it leaves your data uninitialized, so the contents of the array are undefined. There's a function called calloc that does initialize it to zeros.
Also, a style tip. You might try to cast the result of a malloc call to a pointer for the type of data you will store in it (for example, int *array = (int *)malloc(sizeof(int) * 10);. This is frowned upon by C programmers for reasons explained in this post.