Why is the pointer to pointer arithmatic failing in my conditional statment? - c

sm is a 2D array of character pointers allocated dynamically. I need to understand why my pointer to pointer arithmetic is failing in conditional if in loop structure.
2nd column in sm is where the string is that I need to test with the grade key gk which is array of characters/string. s holds row size and q is column size for 2D array, hm is my heap memory counter for freeing function which is not importing for my question.
double *cals(char **sm, char *gk, int s, int q, unsigned *hm) {
int c = 0;
double *savg = malloc(s * sizeof(double));
assert(savg);
*hm += 1;
for (int i = 0; i < s; *(savg + i) = c / q * 100 , c = 0, ++i) {
for (int j = 0; j < q; ++j) {
if (*(*(sm + i * STUDENTATT + 1) + j) == *(gk + j))
++c;
}
}
return savg;
}

There isn't much information given about the purpose of cals function so I had to make a few assumptions to write this answer.
Assumption-1(meaningful):-
You want to find how much characters in the two strings are equal(no every characters) and then find the percentage of the same characters to the total characters. If that is the case use the below code.
double *cals(char **sm, char *gk, int s, int q, unsigned *hm) {
float c = 0; // To force float division the c is declared as a float variable
double *savg = malloc(s * sizeof(double));
assert(savg);
*hm += 1;
char* sm_i_key = NULL;
unsigned int strlen_gk = strlen(gk);
unsigned int key_length = string_gk;
for (int i=0; i<s; ++i) { //The calculation is moved inside for loop
sm_i_key = *(sm+i*q+1); // You can also use sm_i_key = &sm[i*q+1]
/* Uncomment this section if length of 2 strings are not bound to be equal
if(strlen(sm_i_key) < strlen_gk){
key_length = sm_i_key;
}
else{
key_length = strlen_gk
}
*/
for (int j = 0; j < key_length; ++j) {
if (sm_i_key[j] == gk[j])
++c;
}
savg [i] = c / strlen_gk * 100; /* Since gk is the grade key it is assumed
to be equal to the total number.*/
c = 0;
}
return savg;
}
Assumption-2:-
You want to check whether the strings whose starting address is stored in the second column of each row of a 2D array sm is equal to the string stored in array pointed by gk and then calculate a value(double).
The function cals only returns 0.0 or 100.0 as the formula avgs[i]=c / q * 100 will only produce 0 if stings are not equal(since integer division c/q will always result in 0 if c is less than q which is the case here) and 100 if strings are equal(Then why use a double to store the value if only 0 and 100 is stored).
If that is the case then what you are doing here is fine unless the array gk and array sm[i][2] have different string length(not q). It would be better to use strncmp to check the equality of string if the string length of two array's are bound to be different.
Use the below code to do that:-
double *cals(char **sm, char *gk, int s, int q, unsigned *hm) {
int c;
char* sm_i_key = NULL;
double *savg = malloc(s * sizeof(double));
assert(savg);
*hm += 1;
for (int i=0; i < s;++i){//The calculation is moved to a static assignment given below
if(strncmp(sm_i_key, gk, strlen(gk) == 0)
{
savg[i] = 100.0; // Since c/q * 100 => 100.0 if q == c
}
else
{
savg[i] = 0.0; /*Since c/q *100 => 0.0 if q < c since integer
division will result in 0.*/
}
}
return savg;
}
I hope it helps.

Related

Segfault after refactoring nested loops

I have some MATLAB code from a digital audio course that I've ported to C. Given an array of numeric data (for example, PCM audio encoded as double-precision floating-point), produce an array of data segments of a specified width and which overlap each other by a specified amount. Here's the relevant code.
typedef struct AudioFramesDouble {
const size_t n, // number of elements in each frame
num_frames;
double* frames[];
} AudioFramesDouble;
/*
* Produce a doubly-indexed array of overlapping substrings (a.k.a windows, frames,
* segments ...) from a given array of data.
*
* x: array of (i.e., pointer to) data
* sz: number of data elements to consider
* n: number of elements in each frame
* overlap: each frame overlaps the next by a factor of 1 - 1/overlap.
*/
AudioFramesDouble* audio_frames_double(register const double x[], const size_t sz, const unsigned n, const unsigned overlap) {
// Graceful exit on nullptr
if (!x) return (void*) x;
const double hop_d = ((double) n) / ((double) overlap); // Lets us "hop" to the start of the next frame.
const unsigned hop = (unsigned) ceil(hop_d);
const unsigned remainder = (unsigned) sz % hop;
const double num_frames_d = ((double) sz) / hop_d;
const size_t num_frames = (size_t) (remainder == 0
? floor(num_frames_d) // paranoia about floating point errors
: ceil(num_frames_d)); // room for zero-padding
const size_t total_samples = (size_t) n * num_frames;
AudioFramesDouble af = {.n = n, .num_frames = num_frames};
// We want afp->frames to appear as (double*)[num_frames].
AudioFramesDouble* afp = malloc((sizeof *afp) + (sizeof (double*) * num_frames));
if (!afp) return afp;
memcpy(afp, &af, sizeof af);
for (size_t i = 0; i < num_frames; ++i) {
/* Allocate zero-initialized space at the start of each frame. If this
fails, free up the memory and vomit a null pointer. */
afp->frames[i] = calloc(n, sizeof(double));
if (!afp->frames[i]) {
double* p = afp->frames[i];
for (long ii = ((long)i) - 1; 0 <= ii; ii--) {
free(afp->frames[--i]);
}
free(afp);
return (void*) p;
}
for (size_t j = 0, k; j < n; ++j) {
if (sz <= (k = (i*hop) + j)) break;
afp->frames[i][j] = x[k];
}
}
return afp;
}
This performs as expected. I wanted to optimize the nested FOR to the following
for (size_t i = 0, j = 0, k; i < num_frames; (j == n - 1) ? (j = 0,i++) : ++j) {
// If we've reached the end of the frame, reset j to zero.
// Then allocate the next frame and check for null.
if (j == 0 && !!(afp->frames[i] = calloc(n, sizeof(double)))) {
double* p = afp->frames[i];
for (long ii = ((long)i) - 1; 0 <= ii; ii--) {
free(afp->frames[--i]);
}
free(afp);
return (void*) p;
}
if (sz <= (k = (i*hop) + j)) break;
afp->frames[i][j] = x[k];
}
This actually compiles and runs just fine; but in my testing, when I try to access the last frame as in
xFrames->frames[xFrames->num_frames-1],
I get a segmentation fault. What's going on here? Am I neglecting an edge case in my loop? I've been looking over the code for awhile, but I might need a second set of eyes. Sorry if the answer is glaringly obvious; I'm a bit of a C novice.
P.S. I'm a fan of branchless programming, so if anyone has tips for cutting out those IFs, I'm all ears. I was using ternary operators before, but reverted to IFs for readability in debugging.
Remember that the logical operator && and || does short-circuit evaluation.
That means if j != 0 then you won't actually call calloc, and you'll have an invalid pointer in afp->frames[i].

C Keep Getting Double Free, despite trying to free in same form as allocation

Hey I'm trying to do a simple machine learning application for school but I keep getting double free for some reason I cannot even fathom.
float * evaluate(Network net,float * in)
{
int i,j;
float * out;
Neuron cur_neu;
for(i=0,j=0;i<net.n_lay;i++) j = net.lay_sizes[i]>j?net.lay_sizes[i]:j; //Calculating the maximum lay size for output storage
out = (float *) malloc(j*sizeof(float));
for(i=0;i<net.n_lay;i++) //Cycling through layers
{
for(j=0;j<net.lay_sizes[i];j++) //Cycling through Neurons
{
cur_neu=net.matrix[i][j];
out[j] = cur_neu.af(cur_neu.w,in,net.lay_sizes[i-1]); //Storing each answer in out
}
for(j=0;j<net.lay_sizes[i];j++) in[j] = out[j]; //Transfering answers to in
}
return out;
}
float loss(Network net, float **ins_orig, int t_steps)
{
float **profecies;
float st = .5f;
int d_steps = 4;
int t, i, j;
int out_size = net.lay_sizes[net.n_lay - 1];
int in_size = net.lay_sizes[0];
float out = 0.0f;
float **ins;
/*
d_steps = Divination Steps: Number of time steps forward the network has to predict.
The size of the output layer must be d_steps*#ins (deconsidering any conceptual i/os)
t_steps = Total of Steps: Total number of time steps to simulate.
*/
//Copying ins
ins = (float **)malloc(t_steps * sizeof(float *));
for (i = 0; i < t_steps; i++) //I allocate memory for and copy ins_orig to ins here
{
ins[i] = (float *)malloc(in_size * sizeof(float));
for (j = 0; j < in_size; j++)
ins[i][j] = ins_orig[i][j];
}
//
profecies = (float **)malloc(t_steps * sizeof(float *));
for (t = 0; t < t_steps; t++)
{
profecies[t] = evaluate(net, ins[t]);
/*
Profecy 0:
[[a1,b1,c1,d1]
[e1,f1,g1,h1]
[i1,j1,k1,l1]]
Profecy 1:
[[e2,f2,g2,h2]
[i2,j2,k2,l2]
[m2,n2,o2,q2]]
Verification for:
t=0:
loss+= abs(a1-ins[t][0]+b2-ins[t][1]...)
t=1:
t=0:
loss+= abs(e1-ins[t][0]+f2-ins[t][1]...)
*/
for (i = 0; i < d_steps; i++) //i is distance of prediction
{
if (i <= t) // stops negative profecy indexing
{
for (j = 0; j < in_size; j++)
{
out += (ins[t][j] - profecies[t-i][j+in_size*i]) * (ins[t][j] - profecies[t-i][j+in_size*i]) * (1 + st*i); //(1+st*i) The further the prediction, the bigger reward
}
}
}
}
//Free ins
for (i = 0; i < t_steps; i++) //I try to free it here, but to no avail
{
free(ins[i]);
}
free(ins);
return out;
}
I realize it's probably something very obvious but, I can't figure it out for the life of me and would appreciate the help.
Extra details that probably aren't necessary:
evaluate just passes the input to the network (stored in ins) and returns the output
both inputs and outputs are stored in float "matrixes"
Edit: Added evaluate
In your loss() you allocate the same number of floats for each ins:
ins[i] = (float *)malloc(in_size * sizeof(float));
In your evaluate() you calculate the longest lay_size, indicating that it may NOT be net.lay_sizes[0]:
for(i=0,j=0;i<net.n_lay;i++) j = net.lay_sizes[i]>j?net.lay_sizes[i]:j; //Calculating the maximum lay size for output storage
Then you are writing out-of-bounds here:
for(j=0;j<net.lay_sizes[i];j++) in[j] = out[j]; //Transfering answers to in
From that point, your memory is corrupted.

dynamic allocation - pointer to pointer in c

i got exercise from school.
I need to write a function that get array of grades, the size of the array, int number that represent the range of the grades, array that represent the count of the number of the grades in the same range and array that sum the grade of in the range.
the function will create sub groups to the grades, for exmaple: if the range of the grades is 10 so that sub groups is: 0-9, 10-19, 20-29, 30-39,...,90-99,100.
the range is 10 so the number of the sub-groups is 100/range + 1 (11 in that example which the range is 10).
the function will return array that is pointer to pointer, each element in this array will represent the sub-group by ASC.
if there is no values in the range (sub-group) we need to set NULL.
the count array will count the number of the grade in the same range,
and the sum array will sum those grades.
we can assume that the size of those arrays are also 100/range + 1.
important: i need to use dynamic allocate memroy.
i think i have the problem to calculate to which index in the range i need to put the grade, it work in some cases, but not to all.
examples:
int grades[SIZE_GRADES] = {98,45,77,65,89,90,100,43,54,67,55,88,76,67,33,23,45,76,72,76};
int avg_grd1[100 / GRD_RANGE1 + 1];
int avg_grd2[100 / GRD_RANGE2 + 1];
int count_grd1[100 / GRD_RANGE1 + 1];
int count_grd2[100 / GRD_RANGE2 + 1];
int** arr1 = GradeStat(grades, SIZE_GRADES, GRD_RANGE1, count_grd1, avg_grd1);
int** arr2 = GradeStat(grades, SIZE_GRADES, GRD_RANGE2, count_grd2, avg_grd2);
#define GRD_RANGE1 10
#define GRD_RANGE2 7
#define SIZE_GRADES 20
those are working for me.
but what i insert this arrays it didn't: (same vars, just different array).
int grades[SIZE_GRADES] = { 45,46,58,68,70,73,74,78,90,94 };
#define GRD_RANGE1 10
#define GRD_RANGE2 15
#define SIZE_GRADES 10
and that's my code:
int** GradeStat(int* Grades, int size_grades, int grd_range, int* count_grd, int* avg_grd)
{
int sub_range = 100 / grd_range + 1;
int** class_grd;
int place_in_sub_range;
// alocate memory.
class_grd = (int**)calloc(sub_range, sizeof(int));
if (class_grd == NULL) {
exit(1);
}
for (int i = 0; i < sub_range; i++) {
count_grd[i] = 0;
}
for (int i = 0; i < sub_range; i++) {
avg_grd[i] = 0;
}
for (int i = 0; i < SIZE_GRADES; i++) {
// the index (place) in the pointer of pointer.
place_in_sub_range = Grades[i] / grd_range;
if (place_in_sub_range <= sub_range) {
// create new pointer that relevant to the range.
if (class_grd[place_in_sub_range] == 0) {
// alocate memory, set the grade and set the address of the pointer inside the pointer to pointer array.
int* sub_range_pointer = (int*)calloc(1, sizeof(int));
if (sub_range_pointer == NULL) {
exit(1);
}
// save the grade in the memory.
*sub_range_pointer = Grades[i];
// set the pointer address in the poinet of pointer array.
class_grd[place_in_sub_range] = sub_range_pointer;
// count the number of grades in each range.
count_grd[place_in_sub_range]++;
// set the grade in the sum array.
avg_grd[place_in_sub_range] = Grades[i];
}
else {
// find out how many elemnts is exist, realloc + add new grade and add the grade to there.
int* sub_range_pointer = (int*)realloc(class_grd[place_in_sub_range], count_grd[place_in_sub_range] * sizeof(int) + sizeof(int));
if (sub_range_pointer == NULL) {
exit(1);
}
// set the grade in the relevant range.
sub_range_pointer[count_grd[place_in_sub_range]] = Grades[i];
// set the pointer address in the poinet of pointer array.
class_grd[place_in_sub_range] = sub_range_pointer;
// raise the number of grades in the relevant range.
count_grd[place_in_sub_range]++;
// set the grade in the sum array.
avg_grd[place_in_sub_range] = (avg_grd[place_in_sub_range] + Grades[i]) / 2;
}
}
//else {
// return NULL;
//}
}
for (int i = 0; i < sub_range; i++) {
if (class_grd[i] == 0) {
class_grd[i] = NULL;
}
}
// return the pointer of pointer array.
return class_grd;
so on arr1 my code is working,
but on the arr2 it isn't.
i see that when i take the 45 or 46 grade and divine it in the range i'm inserting it to the 3 index (and it should be the second).
When I'm running the code through the school test checker i get this error:
timeout: the monitored command dumped core ../runTrain.sh: line 1: 21344 Segmentation fault timeout -k 5s 5s ./MainTrain.exe > ./mainTrain.log

Searching through pointer array to count letter uses

Ok, so I am not looking for an a full answer please. I just don't know where to begin with this. I have a code that is declaring a pointer array full of names. The goal is to write a code to search the names and count each letter that is used.
/*
* Search through each character in s,
* which is array containing n strings,
* and update the global count array
* with the correct character counts.
* Note: check the examples to see
* if the counts should be case
* sensitive or case insensitive.
*/
void letterCount(char * s[], int n){
//Implement this function
int c = 0,x; // This is what I've done and I
char p = 'a', j = 'z'; // don't know where im messing up.
while (s[c] != '\0') { // I know I can't compare pointer
if (s[c] >= p && s[c] <= j ){ // and integer.
x = *s[c] - 'a';
count[x]++;
}
c++;
}
}
/*
* Initialize each value in the global
* count array to zero.
*/
void initializeCount(){
//Implement this function
int i;
for (i = 0; i < 26; i++){ // Also not sure if this is correct.
count[i] = 0;
}
}
The output should count the letter uses into an array called count[26].
Any suggestions please?
s[c] is not a character, it's a pointer, you are comparing pointer and character p which is not valid,
if (s[c] >= p && s[c] <= j ) // here you are comparing address & char, which you shouldn't
rotate one more loop for comparing each char of string.
Modify your code as
void letterCount(char * s[], int n){
//Implement this function
int c = 0,x,i; // This is what I've done and I
char p = 'a', j = 'z'; // don't know where im messing up.
// assuming n is no of string, rotate main loop from 0 to n
while (c<n) {
for(i=0;s[c][i]!='\0';i++) // I know I can't compare pointer
if (s[c][i] >= p && s[c][i] <= j ){ // and integer.
x = s[c][i] - 'a';
count[x]++;
}
c++;
}
}
I hope you got this.

Using pointers in 2D arrays

I'm attempting to store arrays of integers that I read from a file (with a separate function) in a 2D array but I keep having issues with Segmentation fault. I know it's an issue with my pointers but I can't figure out exactly what I'm doing wrong.
Here is my function (takes an integer and compares it with an integer read from a file before storing it in my 2D array).
int **getStopTimes(int stop_id) {
int **result = malloc(sizeof(*result));
char const* const fileName = "stop_times_test.txt";
FILE* txt = fopen(fileName, "r");
char line[256];
int count = 0;
while (fgets(line, sizeof(line), txt) != NULL) {
int *formattedLine = getStopTimeData(line); //getStopTimeData returns a pointer to an array of ints, memory is allocated in the function
if (formattedLine[1] == stop_id) {
result[count] = formattedLine;
count++;
}
}
fclose(txt);
return result;
}
And my main:
int main(int argc, char *argv[]) {
int **niceRow = getStopTimes(21249);
for (int i=0; i<2; i++) { //Only looping 3 iterations for test purposes
printf("%d,%d,%d,%d\n",niceRow[i][0], niceRow[i][1], niceRow[i][2], niceRow[i][3]);
}
free(niceRow);
return 0;
}
getStopTimeData function thats being called (Pulls certain information from an array of chars and stores/returns them in an int array):
int *getStopTimeData(char line[]) {
int commas = 0;
int len = strlen(line);
int *stopTime = malloc(4 * sizeof(*stopTime)); //Block of memory for each integer
char trip_id[256]; //Temp array to build trip_id string
char stop_id[256]; //Temp array to build stop_id string
int arrival_time; //Temp array to build arrival_time string
int departure_time; //Temp array to build departure_time string
int counter;
for(int i = 0; i <len; i++) {
if(line[i] == ',') {
commas++;
counter = 0;
continue;
}
switch(commas) { //Build strings here and store them
case 0 :
trip_id[counter++] = line[i];
if(line[i+1] == ',') trip_id[counter] = '\0';
break;
case 1: //Convert to hours past midnight from 24hr time notation so it can be stored as int
if(line[i] == ':' && line[i+3] == ':') {
arrival_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 2 :
if(line[i] == ':' && line[i+3] == ':') {
departure_time = (line[i-2]-'0')*600 + (line[i-1]-'0')*60 + (line[i+1]-'0')*10 + (line[i+2]-'0');
}
break;
case 3 :
stop_id[counter++] = line[i];
if(line[i+1] == ',') stop_id[counter] = '\0';
break;
}
}
//Assign and convert to ints
stopTime[0] = atoi(trip_id);
stopTime[1] = atoi(stop_id);
stopTime[2] = arrival_time;
stopTime[3] = departure_time;
return stopTime;
}
This line:
int **result = malloc(sizeof(*result));
allocates just memory for one single pointer. (*result is of type int *, so it's a pointer to data -- the sizeof operator will tell you the size of a pointer to data ... e.g. 4 on a 32bit architecture)
What you want to do is not entirely clear to me without seeing the code for getStopTimeData() ... but you definitely need more memory. If this function indeed returns a pointer to some ints, and it handles allocation correctly, you probably want something along the lines of this:
int result_elements = 32;
int **result = malloc(sizeof(int *) * result_elements);
int count = 0;
[...]
if (formattedLine[1] == stop_id) {
if (count == result_elements)
{
result_elements *= 2;
result = realloc(result, result_elements);
}
result[count] = formattedLine;
count++;
}
Add proper error checking, malloc and realloc could return (void *)0 (aka null) on out of memory condition.
Also, the 32 for the initial allocation size is just a wild guess ... adapt it to your needs (so it doesn't waste a lot of memory, but will be enough for most use cases)
The upper answer is good,
just to give you an advice try to avoid using 2D array but use a simple array where you can store all your data, this ensures you to have coalescent memory.
After that, you can access your 1D array with an easy trick to see it like a 2D array
Consider that your 2D array has a line_size
To access it like a matrix or a 2d array you need to find out the corresponding index of your 1d array for given x,y values
index = x + y * line size;
In the opposite way:
you know the index, you want to find x and y corresponding to this index.
y = index / line_size;
x = index mod(line_size);
Of course, this "trick" can be used if you already know your line size

Resources