Allocation of memory, segmentation error in C - c

I have this problem I need to solve. I am given a program which is supposed to allocate memory to create an array of doubles, but something is wrong with it. Basically, main and the function create_array are broken, and I need to fix it. The solution I came up with comes up with a segmentation error and i am not sure why.
First off I decided to delete the "free(array)" in main b/c array is a pointer which does not exist in heap from my understanding.
I tried changing the function "create_array" to the following
void create_array(double *x, unsigned long n) {
double *d = malloc((int)n *sizeof(double));
if(d == NULL){
printf("Sorry Memory Not Available. Program Terminated.\n");
exit(1);
}
x=d;
free(d);
}
Here is what I was provided with:
int main(void) {
printf("\nProgram started...\n");
double *array = NULL;
int n = 20;
create_array(array, n);
if( array != NULL) {
populate_array(array, n);
// displays half of the values of the array
for(int i = 0; i < n/2; i++){
printf("%f\n", *array++);
}
// According to C standard, the program's behaviour, after the following
// call to the function free is considered "Undefined" and needs to be
// fixed.
free(array);
}
printf("Program terminated...\n");
return 0;
}
// THE FOLLOWING FUNCTION IS NOT PROPERLY DESINGED AND NEEDS TO BE FIXED
void create_array(double *x, unsigned long n) {
x = malloc(n *sizeof(double));
if(x == NULL){
printf("Sorry Memory Not Available. Program Terminated.\n");
exit(1);
}
}
void populate_array(double *array, int n) {
int i;
for(i = 0; i < n; i++)
array[i] = (i + 1) * 100;
}
When I run the code with my edit, i get segmentation error. When I run the code with no changes, it simply outputs "program started \n program terminated".

The problem is, in both code and snippet provided, the variable assigned by malloc's return value lives until the function returns. So you need to use pointer-to-pointer. Moreover, in the first snippet, if you free the area allotted already, you can't use the space anymore.
void create_array(double **x, unsigned long n) {
*x = malloc(n *sizeof(double));
if(*x == NULL){
printf("Sorry Memory Not Available. Program Terminated.\n");
exit(1);
}
}
In main, you can call it as create_array(&array, n);.

There are several errors in create_array. x is a local variable, so it will not change. Also, you free the memory after initialization, which in practice makes the whole function useless. Free should be done after you're done with the memory.
Here is a corrected version
void create_array(double **x, unsigned long n) {
double *d = malloc((int)n *sizeof(double));
if(d == NULL){
printf("Sorry Memory Not Available. Program Terminated.\n");
exit(1);
}
*x=d;
}
And then you call it like this:
double *p;
create_array(&p, size);
/* Do something */
free(p);
But, IMHO it would be better to do like this:
double *create_array(size_t n) {
double *d = malloc(n*sizeof(*d));
if(d == NULL){
fprintf(stderr, "Sorry Memory Not Available. Program Terminated.\n");
exit(1);
}
return d;
}
Changes:
Returns the pointer instead of using an output parameter
Use size_t instead of unsigned long
Print errors to stderr insteadd of stdio
Use malloc(size *sizeof(<var>)) instead of malloc(size * sizeof(<type>))
And here is the call:
double *p = create_array(&p, size);
/* Do something */
free(p);

Related

keeps saying Segmentation fault

This code keeps saying segmentation fault.
for(i=0; i<(numTopps-1); i++)
{
if(kcalTopp[i]<kcalTopp[i+1])
{
temp=*kcalTopp[i];
*kcalTopp[i]=*kcalTopp[i+1];
*kcalTopp[i+1]=temp;
}
}
I think above part is a problem.
but I can't figure what is the problem
#include <stdio.h>
#include <stdlib.h>
void sort(int *kcalTopp[], int numTopps);
int main(void)
{
int numTopps, doughPrice, eachToppPrice, kcalDough, i, j, totalKcal, highest, kcalperDol;
scanf("%d %d %d %d", &numTopps, &doughPrice, &eachToppPrice, &kcalDough);
int *kcalTopp;
kcalTopp=(int*)malloc(sizeof(int)*numTopps);
for(i=0; i<numTopps; i++)
{
scanf("%d", &kcalTopp[i]);
}
totalKcal=kcalDough;
highest=totalKcal/doughPrice;
sort(&kcalTopp, numTopps);
for(i=0; i<numTopps; i++)
{
for(j=0; j<=i; j++)
{
totalKcal=totalKcal+kcalTopp[j];
kcalperDol=totalKcal/(doughPrice+i*eachToppPrice);
if(kcalperDol>highest)
{
highest=kcalperDol;
}
}
}
printf("%d", highest);
return 0;
}
void sort(int *kcalTopp[], int numTopps)
{
int temp, i;
for(i=0; i<(numTopps-1); i++)
{
if(kcalTopp[i]<kcalTopp[i+1])
{
temp=*kcalTopp[i];
*kcalTopp[i]=*kcalTopp[i+1];
*kcalTopp[i+1]=temp;
}
}
}
Indeed, your problem is the sort function you described, as you suspected. Are you aware what *kcalTopp[i]=*kcalTopp[i+1]; does exactly? You get as parameter an int *array[] which is equivalent to int **array (you can see it as an array of arrays of ints). So when you tell C to access array[i] you will access the i-th array. This is a pointer, and in fact *kcalTopp[i] will be the first element from the i-th array. What you are doing here is swapping first elements from the arrays, but in practice you have a single array of ints (or more technically, an array of length 1 of arrays). The simplest fix is to write:
temp=(*kcalTopp)[i];
(*kcalTopp)[i]=(*kcalTopp)[i+1];
(*kcalTopp)[i+1]=temp;
just to change the precedence of the operators. Now, what we achieved is: we take the first array from the array list (it's the only one we have, isn't it?) with (*kcalTopp); this is an int *, not int ** anymore. Now you can safely access the i-th element from it.
Without parentheses, you would first access the i-th array, because in *kcalTopp[i], the [i] part will execute before the * part.
Anyway, to simplify things, you are not required to take as parameter an int *kcalTopp[], you can simply take int kcalTop[] or int *kcalTopp and not use * anymore:
temp = kcalTopp[i];
kcalTopp[i] = kcalTopp[i+1];
kcalTopp[i+1] = temp;
The original code in your post is using an extra (unnecessary) layer of indirection for kcalTopp, resulting in attempts to manipulate an array of addresses (pointers) as opposed to manipulating int values pointed to in memory. This in turn is likely to be the reason you are seeing segmentation faults, which occur when attempting to access memory that you do not own. For some input values, and depending on what day you run your program, it may run, and it may crash.
(This is sometimes referred to as undefined behavior, and is the reason that the problem will not always manifest itself, making you think your program is flawless, when it is not.)
The following contains edits to your original code for the purpose of illustrating some of the suggestions in comments. (not to fix every logic error.) The edits do include treating kcalTopp as a pointer to int memory as opposed to an array of int *. See in-line comments for clarifications:
//void sort(int *kcalTopp[], int numTopps);//*kcalTopp[] is an array of pointers
void sort(int *kcalTopp, int numTopps);//*kcalTopp is a pointer to 'int' memory
int main(int argc, char *argv[])
{
int numTopps, doughPrice, eachToppPrice, kcalDough, i, j, totalKcal, highest, kcalperDol;
//scanf("%d %d %d %d", &numTopps, &doughPrice, &eachToppPrice, &kcalDough);
if(argv != 5) //simple reading in of command line args
{
printf("4 input values required. Exiting");
return 0;
}
//note, each of these calls includes simple for test for success before going on
numTopps = strtol(argv[1], (char **) NULL, 10);
if(errno == ERANGE) {printf("argv[1] Bad input, exiting"); return 0;}
doughPrice = strtol(argv[2], (char **) NULL, 10);
if(errno == ERANGE) {printf("argv[2] Bad input, exiting"); return 0;}
eachToppPrice = strtol(argv[3], (char **) NULL, 10);
if(errno == ERANGE) {printf("argv[3] Bad input, exiting"); return 0;}
kcalDough = strtol(argv[4], (char **) NULL, 10);
if(errno == ERANGE) {printf("argv[4] Bad input, exiting"); return 0;}
int *kcalTopp;
//This statement (without cast) is sufficient to create memory for kcalTopp
kcalTopp = malloc(sizeof(int)*numTopps);
if(!kcalTopp)//should always test before using memory
{
printf("memory allocation failed, exiting");
return 0;
}
for(i=0; i<numTopps; i++)
{
scanf("%d", &kcalTopp[i]);
}
totalKcal=kcalDough;
highest=totalKcal/doughPrice;
//sort(&kcalTopp, numTopps);
// ^ not needed
sort(kcalTopp, numTopps);
for(i=0; i<numTopps; i++)
{
for(j=0; j<=i; j++)
{
totalKcal=totalKcal+kcalTopp[j];
kcalperDol=totalKcal/(doughPrice+i*eachToppPrice);
if(kcalperDol>highest)
{
highest=kcalperDol;
}
}
}
printf("%d", highest);
return 0;
}
void sort(int *kcalTopp, int numTopps)//note removal of []
{
int temp, i;
for(i=0; i<(numTopps-1); i++)
{
if(kcalTopp[i]<kcalTopp[i+1])
{
temp=kcalTopp[i];//note removal of '*' from all kcalTopp
kcalTopp[i]=kcalTopp[i+1];
kcalTopp[i+1]=temp;
}
}
}

pointer to dynamic array of pointers to dynamic array of pointer that points to strings

i have a problem with the initialization of the values inside the first dynamic array of pointers
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char*** GetIndexes()
{
int n = 0;
char ***index;
printf("please insert the number of words you want to add to dictionary\n");
scanf("%d", &n);
index = (char***)calloc(n, sizeof(char));
if (index == NULL)
{
printf("allocation Failed");
return;
}
return index;
}
char** GetDefinitions()
{
int n = 0;
char **definition;
printf("please insert the number of defintions you want to add to the word\n");
scanf("%d", &n);
definition = (char**)calloc(n+1, sizeof(char));
if (definition == NULL)
{
printf("allocation failed");
return;
}
return definition;
}
int main()
{
char *** dptr = GetIndexes();
if (dptr == NULL)
{
printf("memory Allocation failed");
}
int indexcount = sizeof(dptr) / sizeof(char),i;
for (i = 0; i < indexcount; i++)
{
printf("word number %d\n", i + 1);
*dptr[i] = GetDefinitions();
}
printf("%p",dptr);
}
i tried running the debugger in VS2013 and after i enter the number of defintions i want it crashed with this message:
Unhandled exception at 0x01103FB0 in ConsoleApplication1.exe: 0xC0000005: Access violation writing location 0x00000000.
i missed an allocation of something but i cant quite figure out what i missed,
thanks in advance
Your program is very broken
You allocate n char ***s but only request space for n chars and also do it for char **, to prevent this kind of mistake you may use the sizeof operator this way
char ***index;
index = calloc(n, sizeof(*index));
and
char **definition;
definition = calloc(n, sizeof(*definition));
and as you see casting calloc makes it harder and it's not necessary.
You have a return statement that doesn't return anything an GetIndexes() as well as one in GetDefinitions.
They should return NULL if you want to handle failure in the caller function
return NULL;
You erroneously use the sizeof operator to determine the number of char *** pointer allocated in
int indexcount = sizeof(dptr) / sizeof(char)
this will be either 4 or 8 depending on the architecture i.e. the size of a pointer divided by 1 sizeof(char) == 1 always.
You can't compute that value, you simply have to keep track of it. The size
You dereference the triple pointer twice and try to assign a double pointer to it
*dptr[i] = GetDefinitions();
here the operator precedence is also an issue, but regardless of that, this is wrong, may be what you meant was
dptr[i] = GetDefinitions();
This is not going to make your program crash, but it's certainly important to free all malloced pointers before exiting the program.
Here is a suggestion for your code to work, ignore it's purpose since it's not clear what you are trying to do
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char ***GetIndexes(unsigned int *count)
{
char ***index;
printf("please insert the number of words you want to add to dictionary > ");
scanf("%u", count);
index = calloc(*count, sizeof(*index));
if (index == NULL)
{
printf("allocation Failed");
return NULL;
}
return index;
}
char **GetDefinitions(unsigned int *count)
{
char **definition;
printf("please insert the number of defintions you want to add to the word > ");
scanf("%u", count);
definition = calloc(*count + 1, sizeof(*definition));
if (definition == NULL)
{
printf("allocation failed");
return NULL;
}
return definition;
}
int main()
{
unsigned int indexCount, i;
char ***dptr = GetIndexes(&indexCount);
if (dptr == NULL)
{
printf("memory Allocation failed");
}
for (i = 0; i < indexCount; i++)
{
unsigned int definitionsCount;
printf("Word number %u\n", i + 1);
dptr[i] = GetDefinitions(&definitionsCount);
if (dptr[i] != NULL)
{
/* use dptr[i] here or maybe somewhere else, but when you finish */
free(dptr[i]);
}
}
printf("%p", dptr);
/* now if you are done using dptr */
free(dptr);
return 0;
}
As already mentioned in the comment this is a very bad idea and just using double pointers is good here. But the below fixes should be done if you want to use pointers to allocate memory
index = calloc(n, sizeof(char));
should be
index = calloc(n, sizeof(char **));
and
definition = calloc(n+1, sizeof(char));
should be
definition = calloc(n+1, sizeof(char *));

Segfault in my csv_loader() function

I'm trying to write a csv parser in C, but every time I get a segfault in this function. I don't know how to fix it.
char*** csv_loader(char *filename){
FILE* file_xx;
file_xx = fopen(filename, "r");
if(file_xx==NULL){
printf("Failed to open File, no such file or directory!\n");
return 0;
}
int c_=0;
int **linenumbers;
int l=lines(filename);
linenumbers=malloc(sizeof(int)*l);
char*** loaded_csv;
int counter_line=0;
int counter_row=0;
loaded_csv=malloc(sizeof(char **) *l);
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
if(NULL==loaded_csv){
printf("Failed to initialize 'char** loaded_csv'!\n");
return 0;
}
int c_c=0;
int *cm=get_column_map(filename);
for(c_c=0;c_c<l;c_c++){
loaded_csv[c_c]=malloc(sizeof(char *)*cm[c_c]);
}
while(c_!=EOF){
c_=getc(file_xx);
if(c_=='\n'){
linenumbers[counter_line][cm[counter_line]]=counter_row+2;
loaded_csv[counter_line][cm[counter_line]]=malloc(counter_row*sizeof(char));
if(NULL == loaded_csv[counter_line][cm[counter_line]]){
return 0;
}
loaded_csv[counter_line][counter_row]='\0';
counter_row=0;
counter_line++;
}else{
if(c_==','){
counter_row=0;
}else{
counter_row++;
}
}
}
fclose(file_xx);
FILE*fgetsread;
fgetsread=fopen(filename, "r");
int ident, ident_c;
for(ident=0;ident<l;ident++){
for(ident_c=0;ident_c<cm[ident];ident_c++){
fgets(loaded_csv[ident][ident_c], linenumbers[ident][ident_c], fgetsread);
loaded_csv[ident][ident_c][linenumbers[ident][ident_c]-2]='\0';
}
}
fclose(fgetsread);
free(linenumbers);
return loaded_csv;
}
The Debugger says it's this line:
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
Does anyone know what's the bug? I'm yet new to C and anyway try to understand the malloc thing...
PS: the other functions are here: http://pastebin.com/VQZ4d5UU
So, you've allocated space on the line right before:
loaded_csv=malloc(sizeof(char **) *l);
That is fine and dandy, but loaded_csv[0] isn't yet initialized to somewhere you own. So, when you do the following line
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
you are trying to set a variable located in some random location (wherever loaded_csv[0] happens to be right then).
If you want to touch loaded_csv[0][0], you'll have to make sure that loaded_csv[0] is pointing to valid memory first (probably by allocating memory for it via malloc before you allocate something for loaded_csv[0][0].)
You've got a problem with this line:
loaded_csv[0][0]=malloc(getfirstcolumn(filename)*sizeof(char)+2);
Which suggest you are not allocating and initializing loaded_csv[0][0] right.
Here is an example of how to initialize and use a char ***var:
#include <windows.h>
#include <ansi_c.h>
char *** Create3D(int p, int c, int r);
int main(void)
{
char ***pppVar;
pppVar = Create3D(10,10,10);
//test pppVar;
strcpy(pppVar[0][0], "asdfasf");
strcpy(pppVar[0][1], "the ball");
return 0;
}
char *** Create3D(int p, int c, int r)
{
char *space;
char ***arr;
int x,y;
space = calloc (p*c*r*sizeof(char),sizeof(char));
arr = calloc(p * sizeof(char **), sizeof(char));
for(x = 0; x < p; x++)
{
arr[x] = calloc(c * sizeof(char *),sizeof(char));
for(y = 0; y < c; y++)
{
arr[x][y] = ((char *)space + (x*(c*r) + y*r));
}
}
return arr;
}
Be sure to keep track of and free(x) appropriately.

Retaining memory allocated in function body

In one of the programs, I created a function whose one argument was a pointer. The function dynamically allocated some memory to the pointer and returned the size of allocated memory along with other details. But, the allocated memory is destroyed as soon as the function is executed.
How can I retain access and data integrity outside the function to the memory allocated inside the function?
Here's the code modified after reading the replies:
void initialize(int **arr)
{
int i = 0;
*arr = malloc(sizeof(int) * 10);
for (; i < 10; ++i)
*arr[i] = i + 1;
for (i = 0; i < 10; ++i)
printf("\n%d", *arr[i]);
}
int main()
{
int i = 0;
int *arr;
initialize(&arr);
for (; i < 10; ++i)
printf("\n%d", arr[i]);
return 0;
}
But when I run it, it says "rr.exe has stopped working"; although it compiles successfully. Nothing gets printed, not even from the printf in the the function.
Do not call free() on the pointer received by the dynamical allocation, but return it from the function to the calling process.
Example:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
/* give_me_memory(void ** ppv, size_t n) allocates n bytes to *ppv. */
/* The function returns 0 on success or -1 on error. On error errno is set accordingly. */
int give_me_memory(void ** ppv, size_t n)
{
if (NULL == ppv)
{
errno = EINVAL; /* Bad input detected. */
return -1;
}
*ppv = malloc(n);
if (NULL == *ppv)
{
return -1; /* malloc() failed. */
}
return 0; /* Getting here mean: success */
}
int main(void)
{
void * pv = NULL;
if (-1 == give_me_memory(&pv, 42))
{
perror("give_me_memory() failed");
return 1;
}
/* Do something with the 42 bytes of memory. */
free(pv);
return 0;
}
I guess your function looks like:
void f(int *pointer)
{
pointer = (int*)malloc(sizeof(int));
}
this is bad because, your function gets a copy of pointer. Imagine your function takes int as argument and changes its value. Original variable passed to function won't changed, because you passed it as a copy. Here We have the same - you can modify what's poitner pointing at, but not pointer itself.
What do we do when we want to pass variable to function so it can be changed inside? We pass it as a pointer. here You need to do the same - pass pointer to pointer:
void f(int **pointer)
{
*pointer = (int*)malloc(sizeof(int));
}
and call it like this:
int *p = 0;
f(&p);

attempt to free memory causes error

I have declared the following struct:
typedef struct _RECOGNITIONRESULT {
int begin_time_ms, end_time_ms;
char* word;
} RECOGNITIONRESULT;
There is a method that creates an array of RECOGNITIONRESULT and fills it (for test purposes only):
void test_realloc(RECOGNITIONRESULT** p, int count){
int i;
*p = (RECOGNITIONRESULT *)realloc(*p, count * sizeof(RECOGNITIONRESULT));
for (i = 0; i < count; i++){
(*p)[i].begin_time_ms = 2*i;
(*p)[i].end_time_ms = 2*i+1;
(*p)[i].word=(char *) malloc ( (strlen("hello"+1) * sizeof(char ) ));
strcpy((*p)[i].word,"hello");
}
}
The method to free memory is:
void free_realloc(RECOGNITIONRESULT* p, int count){
int i = 0;
if(p != NULL){
if (count > 0){
for (i = 0; i < count; i++){
free(p[i].word); //THE PROBLEM IS HERE.
}
}
free(p);
}
}
The main method calls those methods like this:
int main(int argc, char** argv)
{
int count = 10;
RECOGNITIONRESULT *p = NULL;
test_realloc(&p,count);
free_realloc(p,count);
return 0;
}
Then if I try to free the memory allocated for "word", I get the following error:
HEAP CORRUPTION DETECTED: after normal block (#63) at 0x003D31D8.
CRT detected that the application wrote to memory after end of heap buffer.
Using the debugger I've discovered that the crash occurs when calling free(p[i].word);
What am I doing wrong? How can I free he memory for the strings?
The problem is in your allocation of memory for word. strlen("hello"+1) should be strlen("hello")+1.
Since you appear to allocate a whole array of structures in one strike
RECOGNITIONRESULT **p;
*p = (RECOGNITIONRESULT *)realloc(*p, count * sizeof(RECOGNITIONRESULT));
you can free them in one call to free() as well :
void free_realloc(RECOGNITIONRESULT *p, int count){
free(p);
}
And the strlen("hello"+1) is also wrong, as detected by Chowlett.

Resources