I am aware of the low quality of the code, I am a beginner to programming in C.
The following program attemps to receive input from the user, turn it into tokens and then perform basic math with them. If the input exceeds 8 characters: ('256 + 256'), it fails to properly return a correct result, instead 256 + 256 is interpreted as `256 + 25.
It's been hours and hours of debugging and I cannot pinpoint the error.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX 1024
typedef struct tokenReturn {
int arrayMembers;
char* tokens[];
}
t_return;
t_return *getAndTokenize(char* delim) {
// Get user input and store it as a string literal.
char* input = malloc(1024);
char lit_in[MAX];
if (fgets(input, MAX, stdin) == NULL) {
perror("Error: ");
exit(EXIT_FAILURE);
}
strncpy(lit_in, input, MAX);
free(input);
// Create the return structure to return not only the char* array but the max index as well.
t_return *return_struc = malloc(sizeof(t_return) + MAX);
if (return_struc == NULL) {
puts("Allocation error");
perror("Error");
exit(EXIT_FAILURE);
}
// Assign first member due to the weird behaviour the strtok function has.
char *token = strtok(lit_in, delim);
return_struc->tokens[0] = token;
int i = 1; // We have to start at one since we already have one token stored in the array
while (true)
{
// Check to see if all the tokens have been obtained.
if((token = strtok(NULL, delim)) == NULL) {
break;
}
return_struc->tokens[i] = token;
i++;
}
// Assign i to arrayMembers so that we can determine array length.
return_struc->arrayMembers = i;
return return_struc;
}
float sum(float x, float y) {
return x + y;
}
float multiply(float x, float y) {
return x * y;
}
float subs(float x, float y) {
return x - y;
}
float division(float x, float y) {
return x / y;
}
int main(void) {
// Init
printf("Operation: ");
t_return* tokens = getAndTokenize(" ");
float a = atof(tokens->tokens[0]);
char symbol = tokens->tokens[1][0];
float b = atof(tokens->tokens[2]);
float result;
// Check for the operation being done
switch (symbol) {
case '+':
result = sum( a, b );
break;
case '-':
result = subs(a, b);
break;
case '/':
result = division( a, b );
break;
case '*':
result = multiply( a, b );
break;
default:
puts("Operation not recognized!");
exit(EXIT_FAILURE);
}
printf("Result is: %.3lf\n", result);
exit(EXIT_SUCCESS);
}
getAndTokenize copies the input into lit_in, which is an automatic object inside getAndTokenize. Once getAndTokenize returns, the memory for lit_in is no longer reserved, and the pointers you put into the t_return structure pointing into lit_in are no longer valid. Some of the other code in main does things that reuse that memory for other purposes. Change getAndTokenize to keep the input in an allocated buffer that is not freed until the program is done using the data in it.
Related
I made an attempt to translate a math evaluation I had written in C++ to C. I have faced an issue when I try to loop through the expression and get a segmentation fault.
My tree directory
├── main.c
├── math
│ ├── include.h
│ └── main.c
├── stack
│ ├── include.h
│ └── main.c
My Header and Source File for Stack
//HEADER
#ifndef STACK_H
#define STACK_H
#include <stdio.h>
typedef struct{
int top, max_height;
float data[];
}Stack;
void stack_push(Stack* st, float value);
Stack stack_init(int max);
void stack_replace_top(Stack* st, float value);
void stack_print(Stack* st);
float stack_pop(Stack* st);
int stack_full(Stack* st);
int stack_top(Stack* st);
int stack_height(Stack* st);
int stack_empty(Stack* st);
#endif
//SOURCE
#include <stdio.h>
#include <stdlib.h>
#include "include.h"
int stack_top(Stack* st){return st->top;}
int stack_height(Stack* st){return st->max_height;}
void stack_push(Stack* st, float value){
st->data[st->top] = value;
(st->top)++;
}
float stack_pop(Stack* st){
(st->top)--;
return (st->data[st->top]);
}
Stack stack_init(int max){
return (Stack){0,max};
}
int stack_full(Stack* st){return (st->top >= st->max_height);}
void stack_replace_top(Stack* st, float value){
st->data[st->top - 1] = value;
}
int stack_empty(Stack* st){return (st->top <= 0);}
void stack_print(Stack* st){
int i;
if(st->top == 0){
printf("Stack Is Empty.\n");
}else{
printf("Stack Contents:\n");
for(i=0;i<st->top;i++){
printf("%g\t",st->data[i]);
}
printf("\n\n");
}
}
My Math source, header doesn't have anything important
#include <math.h>
#include <string.h>
#include "include.h"
#include "../stack/include.h"
#include "../utils/include.h"
static float precedence(char op){
switch(op){
case '+':case '-':return 1;
case '*':case '/':return 2;
case '^':case '%':return 3;
default: return 0;
}
return 0;
}
static float apply_op(float a,float b,char op){
switch(op){
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
case '^': return pow(a, b);
case '%': return fmod(a, b);
}
return 0;
}
float evaluate(char* text){
//evaluate a given expression for example (5+5)*7^2
char* token = strtok(text, " ");
//we will use two stacks one for numbers and one for operators
Stack values =stack_init(100);
Stack ops = stack_init(100);
int i=0,size = strlen(token);
printf("Eval: %s\n",token);
printf("4: %c\n",token[4]);
char c;
for(;i<size;i++){
printf("s %d\n",size);
printf("i %d\n",i);
printf("c %c\n",c);
c = token[i];
printf("passed\n");
//if the current character is a number, push it to stack for numbers
switch(c){
case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':{
float val = 0;
//there may be more than one digits in number
while(i < size && c >= '0' && c <= '9'){
val = (val*10) + (c - '0');
c = token[i];
i++;
}
//push the number into stack for numbers
stack_push(&values,val);
//as we are also incrementing the i in above while loop we need to decrement it here
i--;
break;
}
case '(':{
//if current character is an opening brace, push it to 'ops'
stack_push(&ops,'(');
break;
}
case ')':{
while(!stack_empty(&ops) && stack_top(&ops) != '('){
float val2 = stack_pop(&values);
float val1 = stack_pop(&values);
char op = stack_pop(&ops);
stack_push(&values,apply_op(val1,val2,op));
}
//pop opening brace
stack_pop(&ops);
break;
}
case '+': case '-': case '*': case '/': case '^': case '%':{
while(!stack_empty(&ops) && precedence(stack_top(&ops)) >= precedence(c)){
float val2 = stack_pop(&values);
float val1 = stack_pop(&values);
char op = stack_pop(&ops);
stack_push(&values,apply_op(val1,val2,op));
}
//push current operator to 'ops'.
stack_push(&ops,c);
break;
}
}
}
// Entire expression has been parsed at this point, apply remaining ops to remaining values
while(!stack_empty(&ops)){
float val2 = stack_pop(&values);
float val1 = stack_pop(&values);
char op = stack_pop(&ops);
stack_push(&values,apply_op(val1,val2,op));
}
// Top of 'values' contains result, return it
return stack_pop(&values);
}
My mistake appears in the "evaluation" function of the for loop in the math source file. When my loop goes the second time, I get the error. I am really confused because the string the I pass in is "20*2+1" and it is size 6, but when my loop go the second time the index is 4, so it should work. I hope that somebody could help me with my bug.
The problem does not appear to be related to indexing. Instead, your stack implementation is bogus. This ...
typedef struct{
int top, max_height;
float data[];
}Stack;
... declares a structure type with a flexible array member. The flexibility involved is that you can make use of the full amount of space allocated for any given instance of the struct, as if its data member were declared with dimension that made it fill as much of that space as possible. That is useful only in conjunction with dynamic memory allocation, which you are not using, and the resulting dynamically-allocated objects cannot usefully be passed or returned by value.
You have two main options:
If you want to stick with the FAM, then stack_init() must be modified to dynamically allocate large enough instances, and to return a pointer to the allocated result. For example:
Stack *stack_init(int max) {
Stack *rval = malloc(sizeof(*rval) + max * sizeof(rval->data[0]));
if (!rval) {
abort();
}
rval->top = 0;
rval->max = max;
return rval;
}
Other changes would be required to accommodate the change of return type, and to free the dynamically allocated stack objects when they were no longer needed.
OR
Change Stack.data to a pointer, and allocate stack space dynamically . For example:
typedef struct {
int top, max_height;
float *data;
} Stack;
// ...
Stack stack_init(int max) {
float *data = malloc(max * sizof(*data));
if (!data && max != 0) {
abort();
}
return (Stack) { 0, max, data };
}
Of course, here again you need to provide for freeing the allocated memory when it is no longer needed.
--Important Edit--
Thanks for the tip on compiling with -fsanitize=address -g, it allowed me to track down the problem. I'm almost done and I've isolated the issue (which happens near the top of the cleanup function). To simplify things, why does the following (when compiled with the above flags) fail?
#include <stdio.h>
#include <stdlib.h>
struct pair {
char *left;
char *right;
};
int main() {
struct pair *pairs = malloc(100 * sizeof(*pairs));
for (int x = 0; x < 100; x++) {
printf("%i\n", x);
pairs->left = pairs->right = NULL;
pairs += sizeof(*pairs);
}
return 0;
}
After printing 0-7 on new lines, I get ==9803==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61b000000788 at pc 0x00010cb90d88 bp 0x7ffee306fa90 sp 0x7ffee306fa88...Address 0x61b000000788 is a wild pointer.
--Original Question--
I've been working on a brainfuck interpreter in C, but I keep inconsistently getting a segfault. While trying to debug this for a day, I've done many things which, rather than catching where the problem is, simply cause it not to happen. I think at this point I'm encountering undefined behavior, but after rereading my code multiple times I don't see where it could be happening. All of these things cause the program to work as intended:
Printing a variable amount of characters between the bottom of the function body of cleanup and the top of the function body of execute (including inside the main function), though this isn't always consistent
Compiling with the -g flag for debugging
At the top of the execute function
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
changing 30000 to 1000 and 29999 to 999
I've read the documentation on malloc, realloc, and calloc, and browsed for other answers, and I still can't tell the problem. As far as I can tell, I have no memory leaks (even when I realloc a struct pair*, the memory at the pointers within each struct is not leaked because it is within the char *program block) or other issues. That's why I would provide the minimal answer to reproduce the problem, but I'm beginning to doubt that removing seemingly unrelated parts of my source code will have no effect on it (though I have stripped down my code a lot still).
I'm using Mac OS X 10.14, bash "gcc -o brainfc brainfc.c" OR "clang -o brainfc brainfc.c" to compile, "brainfc mandelbrot.b" to run program.
The mandelbrot.b file can be found here: http://esoteric.sange.fi/brainfuck/utils/mandelbrot/mandelbrot.b
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *program = NULL;
struct pair {
char *left;
char *right;
};
//Reads into global variable program from file
void fileinput(char *filename) {
FILE *fp;
fp = fopen(filename, "rb");
if (fp) {
size_t inputlen = 0;
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
rewind(fp);
program = malloc(filesize + 1);
fread(program, filesize, 1, fp);
*(program + filesize) = 0;
fclose(fp);
}
}
//Removes unwanted characters from program, as well as compiling lookup table of pairs
//This happens in a single sweep through the program for efficiency,
//though again this problem might not occur if I optimized for readability
struct pair* cleanup() {
int pairsize = 200;
struct pair *pairs = calloc(pairsize, sizeof(*pairs));
char *src, *dest;
struct pair *buildptr = pairs;
int bracketlevel = 0;
for (src = dest = program; *src; dest += (strchr("<>+-[].,", *src++) != NULL)) {
*dest = *src;
if (*dest == '[') {
bracketlevel++;
while (buildptr->left) {
if (buildptr == pairs + (pairsize - 1) * sizeof(*pairs)) {
pairsize += 100;
pairs = realloc(pairs, pairsize * sizeof(*pairs));
for (int x = 0; x < 100; x++) {
buildptr += sizeof(*pairs);
buildptr->left = buildptr->right = NULL;
}
buildptr -= sizeof(*pairs) * 100;
}
buildptr += sizeof(*pairs);
}
buildptr->left = dest;
} else if (*dest == ']') {
bracketlevel--;
if (bracketlevel < 0) {
return NULL;
}
while (buildptr->right) {
buildptr -= sizeof(*pairs);
}
buildptr->right = dest;
}
}
if (bracketlevel != 0) {
return NULL;
}
*dest = 0;
program = realloc(program, strlen(program) + 1);
return pairs;
}
//Executes program
int execute(struct pair *pairs) {
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
for (char *pc = program; *pc; pc++) {
switch (*pc) {
case '<':
if (pointer == leftbound) return 1;
pointer--;
break;
case '>':
if (pointer == rightbound) return 1;
pointer++;
break;
case '+':
(*pointer)++;
break;
case '-':
(*pointer)--;
break;
case '[':
while (pairs->left != pc) pairs += sizeof(*pairs);
if (!(*pointer)) pc = pairs->right;
break;
case ']':
while (pairs->right != pc) pairs -= sizeof(*pairs);
if (*pointer) pc = pairs->left;
break;
case '.':
printf("%c", *pointer);
break;
case ',':
printf("Inputting 10 (for now)\n");
*pointer = 10;
break;
}
}
return 0;
}
//Parses command line arguments, calls each function in order
int main(int argc, char *argv[]) {
if (argc > 0) {
char *filepath = argv[1];
fileinput(filepath);
}
if (program == NULL) {
printf("Error: File not found\n");
return 3;
}
struct pair *pairs = cleanup();
if (pairs == NULL) {
printf("Error: Invalid program\n");
return 4;
}
int execstatus = execute(pairs);
switch (execstatus) {
case 1:
printf("\nError: Pointer out-of-bounds\n");
return 1;
case 2:
printf("\nError: Byte overflow\n");
return 2;
default:
return 0;
}
}
Any help would be greatly appreciated.
pairs += sizeof(*pairs);
Pointer arithmetic in C is always in units of the type pointed to - here, it's in units of struct pairs. So if you want pairs to point to the next struct pair in the array, add 1. (The compiler will internally translate this into adding the appropriate number of bytes, or however pointers happen to work on your system.) This line should be pairs += 1; or pairs++; or ++pairs; according to your taste.
As it stands, if sizeof(*pairs) happens to be, say, 16 on your system, you are skipping past 15 more struct pairs every time you iterate. You will end up accessing the 0th, 16th, 32nd, ... 1584th struct pair in the array. Since it only contains 100, obviously most of these will be out of bounds. Hence your segfault.
As previously mentioned the usage of pointers is a bit messed up.
Instead of
pairs->left = pairs->right = NULL;
pairs += sizeof(*pairs);
Use
pairs[x].left = pairs[x].right = NULL;
As a bonus you have pairs still intact to do the clean up
I had this problem for a while. I cannot create a gets(int maxChar) function that allows the user to get a char* using a get_char() function.
My current code:
char* gets(int maxChar) {
char a;
char* b;
int i;
for(i = 0; i<maxChar; i = i + 1){
a = getchar();
if (a != 0x0D) {putchar(a);} else {puts("\r\n");break;}
b[sizeof(b)] = a;
}
if (sizeof(b) > maxChar-1) {puts("\r\n");}
return b;
//if (b[sizeof(b)-1] != '')
}
the get_char() function works perfectly.
Full kernel.c: https://pastebin.com/3bqTbHsv
Change
char* b;
to
char* b = (char *)malloc(maxChar);
and
b[sizeof(b)] = a;
to
b[i] = a;
Also, change
if (sizeof(b) > maxChar-1) {puts("\r\n");}
to
if (i > maxChar-1) {puts("\r\n");}
The changes made are:
You have created a pointer, but have not allocated any memory. Hence the malloc statement.
sizeof(b) will always be 4 for a 32-bit compiler. You need the array index, given by i.
Same as 2.
These are the basic changes you need to make, without any change to your logic.
The following is an educated guess at what you were attempting to do. It includes some explanations, and a calling example:
char* _gets(int maxChar) // change name to avoid conflict with library 'gets'
{
//char a; //addresses concern pointed out in comments.
int a; //variable is used by function that can return EOF (-1)
int i=0; //
char* b = calloc(maxChar + 1, 1);//point pointer to memory (that it owns)
if(b) //test for success before going on
{
for(i = 0; i<maxChar-3; i = i + 1) // -3 to leave room for \r\n\0
{
a = getchar();
if ((a != 0x0D) && (a != EOF))
{
putchar(a);
b[i]=a;// place char into string accumulator
}
else break;// either EOF or <ENTER> occurred
} // no need for else in this implementation as we can handle
// the clean up once the conditions are met by outputting
// user's entries, then preparing your string (array) for return
puts("\r\n");
b[i++]='\r';
b[i++]='\n';
b[i++]='\0';
}
else return NULL;//failed to allocate memory. leave
return b; // return b (now a string)
//if (b[sizeof(b)-1] != '') // not sure what this was for
}
int main(void)
{
char *strArray = _gets(10);//creates memory for strArray
if(strArray) //use only if not NULL
{
printf("The array contains: %s", strArray );
free(strArray );
}
return 0;
}
I've been trying to complete exercise 5-10 from K&R using a dynamically allocated stack. I based my code on the code from chapter 4 (they used global variables to implement the stack). The problem is that my programme doesn't work at all and I can't figure out what is wrong. Here's the code:
/* expr: evaluates a reverse Polish expression from the command line */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXOP 100 /* maximal operator length */
#define NUMBER '0' /* signal that a number was found */
int getop(char *argv);
void push(double **top, double val);
double pop(double **top);
int main(int argc, char *argv[])
{
if (argc == 1) {
printf("usage: evaluate a reverse Polish expression from the command line\n");
return 1;
}
double *stack = malloc((argc-1)*sizeof(double));
if (stack == NULL) {
printf("error: couldn't allocate enough space for the stack\n");
return 2;
}
int i, type;
double op1, op2, *top = stack; /* top points to the next free stack position */
char s[MAXOP];
for (i = 1; argv[i] != NULL; i++) {
type = getop(argv[i]);
switch (type) {
case NUMBER :
push(&top, atof(argv[i]));
break;
case '+' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1+op2);
break;
case '-' :
break;
case '*' :
break;
case '/' :
break;
case '%' :
break;
default :
printf("error: unknown command %s\n", argv[i]);
return 3;
break;
}
}
printf(" = %.8g\n", pop(&top));
free(stack);
return 0;
}
int getop(char *argv)
{
int i, c;
if (!isdigit(argv[0]))
return argv[0];
else
return NUMBER;
}
void push(double **top, double val)
{
**top = val;
(*top)++;
/* is error checking needed? */
}
double pop(double **top)
{
(*top)--;
return *(*top+1);
/* is error checking needed? */
}
It seems not to take operators into account - for example input ./expr 1 12 13 + + produces output 13.
EDIT:
Thanks for all the help guys, it turns out that push and pop didn't work properly. I've managed to fix that code, although now from the hindsight I see that I could've prepared better before writing the code.
Here is the code after the changes:
/* expr: evaluates a reverse Polish expression from the command line */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define MAXOP 100 /* maximal operator length */
#define NUMBER '0' /* signal that a number was found */
int getop(char *argv);
void push(double **top, double val);
double pop(double **top);
int main(int argc, char *argv[])
{
if (argc == 1) {
printf("usage: evaluate a reverse Polish expression from the command line\n");
return 1;
}
double *stack = (double*) malloc((argc-1)*sizeof(double));
if (stack == NULL) {
printf("error: couldn't allocate enough space for the stack\n");
return 2;
}
int i, type;
double op1, op2, *top = stack; /* top points to the next free stack position */
char s[MAXOP];
for (i = 1; argv[i] != NULL; i++) {
type = getop(argv[i]);
switch (type) {
case NUMBER :
push(&top, atof(argv[i]));
break;
case '+' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1+op2);
break;
case '-' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1-op2);
break;
case 'x' :
op2 = pop(&top);
op1 = pop(&top);
push(&top, op1*op2);
break;
case '/' :
op2 = pop(&top);
op1 = pop(&top);
if (op2 != 0)
push(&top, op1/op2);
else {
printf("error: division by zero\n");
return 3;
}
break;
default :
printf("error: unknown command %s\n", argv[i]);
return 4;
break;
}
}
printf(" = %.8g\n", pop(&top));
free(stack);
return 0;
}
int getop(char *argv)
{
int i, c;
if (!isdigit(argv[0]))
return argv[0];
else
return NUMBER;
}
void push(double **top, double val)
{
**top = val;
(*top)++;
}
double pop(double **top)
{
double temp = *(*(top)-1);
(*top)--;
return temp;
}
Your code seems to not understand that you allocated an array with malloc, and you're trying to use the "add to front" method that is used with pointer-based stacks. You should be pushing new values after the most recent item pushed onto the stack and popping the item most recently pushed onto the stack (i.e. at the "end" of the stack).
The following should work for you. Note that pcount is a pointer to the number of items on the stack, else you won't know whether the stack is empty (e.g. 2 + would be invalid input because + requires 2 values but there's only 1 on the stack) or even where to add another value because you won't be able to determine where the "end" of the stack is.
#include <math.h> // for HUGE_VAL; may need to link the math library?
// Push a value onto the stack and update the number of items on the stack.
void push(double *stk, double value, int *pcount)
{
// Add new values at the end of the stack (technically after the last item pushed).
stk[*pcount] = value;
++*pcount;
}
// Pop a value off the stack and update the number of items remaining on the
// stack. If there are no values, HUGE_VAL is returned. Since it is possibly
// a valid value on some implementations, checking for an error should be done
// using the value pcount points to:
//
// n = pop(stk, &stkCount);
// if (stkCount < 0) {
// // error: stack had no elements before pop
// }
//
double pop(double *stk, int *pcount)
{
if (*pcount >= 0) {
// Remove items from the end of the stack.
--*pcount;
return stk[*pcount];
}
return HUGE_VAL;
}
As #AnttiHaapala pointed out, your push and pop are a mess. Also, your data is organized in a way that makes error checking difficult, if not impossible.
Here are correct push and pops.
typedef struct
{
double* base; // base address of stack, allocated with malloc.
double* end; // top address of stack + 1 double, init to base + number of elements
double* ptr; // stack pointer, initialize to equal base
} stack;
int init_Stack(struct stack* p, int items)
{
p->base = malloc(items * sizeof(double));
if (!p->base)
return -1;
p->end = p->base + items;
p->ptr = p->base;
return 0;
}
void push(struct stack* p, double val)
{
if (p->ptr >= p->end)
{
//stack overflow!
exit(3);
}
*(p->ptr++) = val;
}
double pop(struct stack* p)
{
if (p->ptr <= p->base)
{
// stack underflow!
exit(4);
}
return *(--(p->ptr));
}
I am working on a c code that holds a structure that hosts some values which I call range.
My purpose is to use this so called range dynamically (holding different amount of data at every execution). I am now provisionally using the # define comp instead. This so called range gets updated every time I call my update_range though the use of s1 structure (and memory allocations).
What I found weird is that when I introduced a "show_range" function to output the actual values inside/outside the update function I realized that I loose the first two values.
Here is the code.
Any suggestions on that?
Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <complex.h>
#define comp 1024
// struct holding a complex-valued range
struct range {
int dimensions; /* number of dimensions */
int* size; /* array holding number of points per dimension */
complex double* values; /* array holding complex valued */
int components; /* number of components that will change on any execution*/
};
// parameters to use in function
struct s1 {
int tag;
struct range* range;
};
int update_range(struct s1* arg);
int show_range(struct range* argrange, char* message);
int copy_range(struct range* in, struct range* out);
int main(void) {
int ret = 0;
struct s1 s1;
s1.tag = 0;
s1.range = malloc(sizeof(struct range));
update_range(&s1);
show_range(s1.range, "s1.range inside main function");
return ret;
}
////////////////////////////////////////////
int update_range(struct s1* arg) {
int ret = 0;
int i;
struct range range;
range.dimensions = 1;
range.size = malloc(range.dimensions * sizeof(int));
range.components = comp;
range.size[0] = range.components; // unidimensional case
range.values = malloc(range.components * sizeof(complex double));
for (i = 0; i < range.components; i++) {
range.values[i] = (i + 1) + I * (i + 1);
}
show_range(&range, "range inside update_range function");
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown
copy_range(&range, arg->range);
show_range(arg->range, "arg->range inside update_range function");
if (range.size)
free(range.size);
range.size = NULL;
if (range.values)
free(range.values);
range.values = NULL;
return ret;
}
////////////////////////////////////////////
// Show parameters (10 first values)
int show_range(struct range* argrange, char* message) {
int ret = 0;
vint i;
printf(" ******************************\n");
printf(" range in %s \n", message);
printf(" arg.dimensions=%d \n", argrange->dimensions);
printf(" arg.size[0]=%d \n", argrange->size[0]);
printf(" argrange.components=%d \n", argrange->components);
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
printf("\n");
return ret;
}
////////////////////////////////////////////
// copy range
int copy_range(struct range* in, struct range* out) {
int ret = 0;
if (in == NULL) {
fprintf(stderr, "error: in points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
if (out == NULL) {
fprintf(stderr, "error: out points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
out->dimensions = in->dimensions;
out->size = in->size;
out->values = in->values;
out->components = in->components;
cleanup:
return ret;
}
Your copy_range function is broken, because it copy only pointer to size and values and not the memory. After you call free(range.size); and free(range.values); you are deleting mamory also from original object but without setting its pointers back to NULL.
After calling update_range, s1.range has non NULL pointers in size and values, but they are pointing to deleted memory.
You are experiencing undefined behaviour (UB) due to accessing freed memory. Your copy_range() function only does a shallow copy of the two pointer fields so when you run free(range->size) you make arg->range->size invalid.
You should make copy_range() a deep copy by allocating and copying the pointer contents like:
out->size = malloc(in->dimensions * sizeof(int));
memcpy(out->size, in->size, in->dimensions * sizeof(int));
out->values = malloc(in->components * sizeof(complex double));
memcpy(out->values , in->values, in->components * sizeof(complex double));
There are not 10 items to print, so the lines:
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
Will be printing from random memory.
a much better method would be:
printf(" first %d {Re} values: \n", min(argrange.components,10));
for (i = 0; i < argrange.components; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
The above is just one of many problems with the code.
I would suggest executing the code using a debugger to get the full story.
as it is, the code has some massive memory leaks due mostly
to overlaying malloc'd memory pointers.
for instance as in the following:
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown