I want to perform a simple task working with function pointers in C.
The task is to get an array (from any type, i.e: int / char*), and sum /concatenate each 2 elements in the array.
for the char* type, it works fine, but for the int type, the loop seems to jump each 2 elements in the array (and thus overflow the array):
#define N1 4
#define N2 4
typedef void*(*Fn_Sum)(void*, void*);
typedef void(Fn_Prt)(void*);
int sum_num(int a, int b){
return a + b;
}
char* sum_char(char* a, char* b){
char *result = malloc(strlen(a) + strlen(b) + 1);
if (!result) {
printf("ERROR: malloc failed !\n");
return NULL;
}
strcpy(result, a);
strcat(result, b);
return result;
}
void print_num(int a){
printf("%d", a);
}
void print_string(char* a){
int i = 0;
while (a[i] != '\0') {
printf("%c", a[i]);
i++;
}
}
void PrintSums(void** P, int n, Fn_Sum fsum, Fn_Prt fprt){
for(int i = 0; i < n - 1; i++){
(fprt)(fsum(P[i], P[i+1]));
printf(", ");
}
printf("\n");
}
int main() {
int V[N1] = {1,2,3,4};
char* S[N2] = {"a", "d", "c", "d"};
PrintSums(V, N1, sum_num, print_num);
PrintSums(S, N2, sum_char, print_string);
return 0;
}
expected output is :
3, 5, 7,
ab, bc, cd,
actual outputs:
4, 725939, 4925336,
ad, dc, cd,
Create an abstract interface for iterator over the elements. A draft of such interface could look like this:
struct iterator {
...
};
// ptr - a pointer to beginning of the array
// size - size of one element in the array
void it_init(iterator *t, void *ptr, size_t size);
bool it_eq(iterator *t, iterator *o); // compare iteratores
void it_add(iterator *t, size_t n);
void it_inc(iterator *t);
// return a pointer to the element
void *it_get(iterator *t);
Remember to always pass to user callbacks a context variables. Otherwise users will have to use global variables, which make code messy. Create an abstract interface with destructors and constructors of your summing object. Handle errors properly:
// is passed a pointer to user context
// returns 0 on success
typedef int (*Fn_Sum)(void*, void*);
// is passed a pointer to user context
// returns 0 on success
typedef int (Fn_Prt)(void*);
// returns 0 on success
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx);
After that, implement objects that expose the interface that you want:
struct num { .. };
void num_sum(struct num *t, int el);
void num_print(struct num *t, int el);
// expose interface to PrintSums
// that just calls internal api
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
An example whole program looks like this:
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// iterator
typedef struct iterator {
void *ptr;
size_t size;
} iterator;
void it_init(iterator *t, void *ptr, size_t size) {
*t = (iterator){ ptr, size, };
}
// eq is from test(1) shell command. "eq" means "equal"
bool it_eq(iterator *t, iterator *o) {
return t->ptr == o->ptr;
}
void it_add(iterator *t, size_t n) {
t->ptr = (char*)t->ptr + t->size * n;
}
// increment the iterator
void it_inc(iterator *t) {
it_add(t, 1);
}
// return a pointer to the element
void *it_get(iterator *t) {
return t->ptr;
}
// interface
typedef int (*Fn_Sum)(void*, void*);
typedef int (Fn_Prt)(void*);
int PrintSums(iterator it, size_t n, Fn_Sum fsum, Fn_Prt fprt, void *sumctx){
iterator end = it;
it_add(&end, n);
for(; !it_eq(&it, &end); it_inc(&it)) {
int err = fsum(sumctx, it_get(&it));
if (err) return err;
err = fprt(sumctx);
if (err) return err;
printf(", ");
}
printf("\n");
return 0;
}
// num object
struct num {
int sum;
};
void num_init(struct num *t) {
t->sum = 0;
}
void num_sum(struct num *t, int el){
t->sum += el;
}
void num_print(struct num *t){
printf("%d", t->sum);
}
void num_free(struct num *T) {
// nothing, just exists for uniform API
}
// accessors for PrintSums
int num_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct num *t = ctx;
int *el = el0;
num_sum(t, *el);
return 0;
}
int num_PrintSums_Fn_Prt(void *ctx) {
struct num *t = ctx;
num_print(t);
return 0;
}
// string object
struct str {
char *str;
};
void str_init(struct str *t) {
t->str = NULL;
}
int str_sum(struct str *t, const char *str) {
const size_t str_len = t->str == NULL ? 0 : strlen(t->str);
void *p = realloc(t->str, str_len + strlen(str) + 1);
if (p == NULL) {
free(t->str);
t->str = NULL;
return -1;
}
t->str = p;
memcpy(t->str + str_len, str, strlen(str) + 1);
return 0;
}
void str_print(struct str *t) {
if (t->str == NULL) {
printf("(nul)");
} else {
printf("%s", t->str);
}
}
void str_free(struct str *t) {
free(t->str);
}
// interface for PrintSums
int str_PrintSums_Fn_Sum(void *ctx, void *el0) {
struct str *t = ctx;
const char **el = el0;
str_sum(t, *el);
return 0;
}
int str_PrintSums_Fn_Prt(void *ctx) {
struct str *t = ctx;
str_print(t);
return 0;
}
// and finally main
int main() {
int err = 0;
int V[] = {1,2,3,4};
iterator numit;
it_init(&numit, V, sizeof(*V));
struct num numsum; // the object that will hold the sum
num_init(&numsum);
err = PrintSums(numit, sizeof(V)/sizeof(*V), num_PrintSums_Fn_Sum, num_PrintSums_Fn_Prt, &numsum);
if (err) abort();
num_free(&numsum);
char *S[] = {"a", "d", "c", "d"};
iterator strit;
it_init(&strit, S, sizeof(*S));
struct str strsum; // the object that will hold the sum of strings
str_init(&strsum);
err = PrintSums(strit, sizeof(S)/sizeof(*S), str_PrintSums_Fn_Sum, str_PrintSums_Fn_Prt, &strsum);
if (err) abort();
str_free(&strsum); // YES! Remember to pick out the trash
}
and outputs on godbolt:
1, 3, 6, 10,
a, ad, adc, adcd,
The pointers to a constructor and destructor of "sum objects" could be passed to PrintSums too. That said one could start thinking about creating a virtual table for all these pointers (ie. one struct with function pointers that are needed for PrintSums...).
table.h:
#ifndef table_h
#define table_h
// The object:
typedef struct Pair
{
char* name;
int number;
} Pair;
int comp_pair(const void* lhs, const void* rhs)
{
Pair* lp = (Pair*) lhs;
Pair* rp = (Pair*) rhs;
const char* ln = lp->name;
const char* rn = rp->name;
return strcmp(ln, rn);
}
// The array and associated functions:
size_t table_capacity;
size_t table_size;
Pair* table; // <------ Global variables -------------------
Pair* create_table (size_t capacity)
{
Pair* p = 0;
p = (Pair*) malloc(sizeof(*p) * capacity);
if (p == NULL && capacity > 0)
{
perror("create_table()::bad allocation!\n");
exit(-1);
}
table_capacity = capacity;
return p;
}
void insert (Pair* table, const char* name, int number)
{
Pair* p = (Pair*) malloc(sizeof(*p));
if (p == NULL)
{
perror("insert::bad allocation!\n");
exit(-1);
}
p->name = name;
p->number = number;
table[table_size++] = *p;
}
void print_table(Pair p[], size_t size)
{
size_t i = 0;
for (i; i < size; ++i)
{
printf("%s -> %d\n", p[i].name, p[i].number);
}
}
#endif
main.c:
#include <stdio.h>
#include <stdlib.h> // qsort()
#include <string.h> // strcmp()
#include <stddef.h> // size_t
#include "table.h"
int main()
{
char* names [ ] = { "bla1", "bla2", "bla3", "bla4", "bla5"};
int numbers [ ] = { 1, 2, 3, 4, 5 };
size_t s = 5;
size_t i = 0;
table = create_table(s);
for (i; i < s; ++i)
{
insert(table, names[i], numbers[i]);
}
qsort(table, table_size, sizeof(Pair), comp_pair);
print_table(table, table_size);
getchar();
free(table);
}
When I try to use qsort(), (debugging) the above code generates the following error:
Access violation reading location 0x65727541.
Questions:
Is the function comp_pair() correct?
What size should I pass as a third parameter in qsort(), the current sizeof(Pair) or the size of the actually compared types, i.e. char*?
So i'm trying to figure out how to do a few different things and I haven't worked with C that much, so any help would be much appreciated.
typedef int data_t;
typedef struct set {
data_t *array;
size_t capacity;
size_t size;
} set_t;
typedef data_t* set_i_t;
#define CLEAR -1
I have gotten this method working which uses malloc and allocates memory:
int set_init( set_t *set, int capacity ){
set->array = (data_t*)malloc(capacity * sizeof(data_t));
if(set->array == NULL){
return 1;
}
else{
set->capacity = capacity;
set->size = 0;
return 0;
}
}
And a method which frees it:
void set_free( set_t *set ){
free(set->array);
set->array = NULL;
set->capacity = set->size = 0;
}
In a separate method i'm trying to set all the values in the set to -1 (CLEAR)
void set_clear( set_t *set){
int i = 0;
for (i = 0; i < set->size; i++){
set->array = CLEAR;
}
set->size = 0;
}
Return the Size of the set:
int set_size( set_t set ) {
return sizeof(set->array);
}
Return the capacity:
int set_capacity( set_t set ) {
int capacity = set->capacity;
return capacity;
}
And then print the set:
void set_print( set_t set ) {
//Honestly don't feel like i'm ready for this one yet.
}
If anyone could walk me through a couple of these or give me a little assistance on how these can work, that would be awesome. Thanks guys!
A good resource is C dynamically growing array
1
You can read about size_t. What is size_t in C?
typedef int data_t;
// Here you are redefining int to data_t this is then used in array.
typedef struct set {
data_t *array;
// The address on heap where the typedef data_t is stored
size_t capacity;
size_t size;
} set_t;
typedef data_t* set_i_t;
// not sure why this is here maybe you use somewhere else
#define CLEAR -1
2
set_free( set_t *set); Looks good to me.
set_init(); yes but no
set_t set_init(int capacity) {
// create it here then return it.
set_t ret;
ret.array = (data_t*)malloc(capacity * sizeof(data_t));
if (ret.array == NULL) return NULL;
ret.capacity = capacity;
ret.size = 0;
return ret;
}
In the calling function
set_t A = set_init(5);
if (A == NULL) fprintf(stderr, "could not alloc memory\n");
// :)
3
void set_clear( set_t *set){
// you pass the address of the struct into the function. you could also use set_i_t
//int i = 0;
// why do this you can do it in the for loop as you can see
// for (i = 0; i < set->size; i++){
for (int i = 0; i < set->size; i++){
//set->array = CLEAR; common mistake
// you are saying the address of the array. aka array[0]
// this is the same as set->(array+i)
set->array[i] = CLEAR;
}
set->size = 0;
}
4 & 5
// looks good but again better ways of doing this.
set_size( set_t set );
set_capacity( set_t set );
Better ways of managing memory such as in the example here. C dynamically growing array
6
read all about printf();
http://www.tutorialspoint.com/c_standard_library/c_function_printf.htm
void set_print( set_t set ) {
// Here you passed the struct in plain and simple no pointer......
// so you will use the '.' not the '->'
// Here we can take a look at printf();
// %d is used to print int variables.
// to start off you know you will have to loop through the array.
for (int i = 0; i < set.size; i++) {
// you know the array must be at least have one item in it.
printf("%d\n", set.array[i]);
// using printf print the data_t aka "int" item in the array
}
}
Hope this helps. G
There were a few places where you defined the function arguments with set_t instead of set_t *.
Your set_size would just return the size of the array pointer (i.e. always 4 or 8), so that needed set->size
Also, set_clear was incorrect [and wouldn't even compile].
I've added some functions and implemented the [dreaded :-)] print function. No worries ...
Anyway, here's the corrected code [please pardon the gratuitous style cleanup]:
#include <stdio.h>
#include <malloc.h>
typedef int data_t;
typedef struct set {
data_t *array; // pointer to set's data
size_t capacity; // total number of data slots
size_t size; // number of slots currently in use
} set_t;
typedef data_t *set_i_t;
#define CLEAR -1
int
set_init(set_t *set, int capacity)
{
set->array = (data_t *) malloc(capacity * sizeof(data_t));
if (set->array == NULL) {
return 1;
}
else {
set->capacity = capacity;
set->size = 0;
return 0;
}
}
// And a method which frees it:
void
set_free(set_t *set)
{
free(set->array);
set->array = NULL;
set->capacity = set->size = 0;
}
// i'm trying to set all the values in the set to -1 (CLEAR)
void
set_clear(set_t *set)
{
int i = 0;
for (i = 0; i < set->size; i++) {
#if 0
set->array = CLEAR;
#else
set->array[i] = CLEAR;
#endif
}
set->size = 0;
}
// Return the Size of the set:
int
set_size(set_t *set)
{
return set->size;
}
// Return the maximum capacity:
int
set_capacity_max(set_t *set)
{
int capacity = set->capacity;
return capacity;
}
// Return the remaining available capacity:
int
set_capacity_avail(set_t *set)
{
int capacity = set->capacity - set->size;
return capacity;
}
// add some data
void
set_append(set_t *set,int val)
{
// NOTES:
// (1) this does _not_ check for overflow against capacity
// (2) when out of capacity, we might increase capacity and do a realloc
// on array
#if 0
if ((set->size + 1) >= set->capacity) {
set->capacity += 100;
set->array = realloc(set->array,sizeof(data_t) * set->capacity);
}
#endif
set->array[set->size++] = val;
}
// And then print the set:
void
set_print(set_t *set)
{
int i;
int len;
// Honestly don't feel like i'm ready for this one yet.
// Relax, no worries ...
len = 0;
for (i = 0; i < set->size; i++) {
len += printf(" %d",set->array[i]);
if (len >= 72) {
printf("\n");
len = 0;
}
}
if (len > 0)
printf("\n");
}
int
main(void)
{
set_t myset;
set_init(&myset,100);
set_append(&myset,17);
set_append(&myset,23);
set_append(&myset,37);
set_print(&myset);
set_free(&myset);
return 0;
}
I am having an error with the code we are using, was wondering if someone could help debug. Seems like we are getting a malloc error. Thanks.
void readWords(char norm_word[MAXSIZE], Word ** array) {
int i = 0;
bool found = false;
int result = 0;
Word * current_pointer = malloc (sizeof(Word*));//creates a temporary variable for each pointer in the array
for (i=0; i<word_counter; i++) {
current_pointer = *(array+i); //accesses the current pointer
result = strcmp(norm_word, (current_pointer -> word)); //compares the string to each stored string
if (result == 0) {
found = true;
(current_pointer->freq)++;
break;
}
}
if(!found) {
if(pointer_counter == word_counter) {
array = realloc(array, sizeof(array)*2);
pointer_counter*=2;
}
Word * new_pointer = (Word*) malloc (sizeof(Word*));
strcpy(new_pointer -> word, norm_word);
*(array + (pointer_counter - 1)) = new_pointer;
word_counter++;
}
;
}
All pointers have the same size on your system. So a sizeof always returns the same size for any pointer. You want to allocate for the structure, so you need to use sizeof on the name without the star. malloc will return the pointer to that block of memory afterwards.
Here is a short implementation:
#include <iostream>
#include <string>
typedef struct
{
int num;
int numnum;
}numbers;
int main(int argc, char ** argv)
{
numbers* n = (numbers*)malloc(sizeof(numbers));
n->num = 1;
n->numnum = 2;
free(n);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAXSIZE 64
typedef struct word {
char word[MAXSIZE];
int freq;
} Word;
int word_counter = 0;
size_t pointer_counter = 16;//Number of pointers that ensure
void readWords(char norm_word[MAXSIZE], Word ** array) {
int i = 0;
bool found = false;
Word *current_pointer = *array;
for (i=0; i<word_counter; i++) {
if(strcmp(norm_word, current_pointer->word) == 0){
found = true;
current_pointer->freq++;
break;
}
++current_pointer;
}
if(!found) {
if(pointer_counter == word_counter) {
pointer_counter *= 2;
*array = realloc(*array, sizeof(Word)*pointer_counter);
}
Word *new_pointer = *array + word_counter;
new_pointer->freq = 1;
strcpy(new_pointer->word, norm_word);
++word_counter;
}
}
int main(void){
Word *vocabulary = calloc(pointer_counter, sizeof(Word));
char norm_word[MAXSIZE];
while(1==scanf("%s", norm_word)){
readWords(norm_word, &vocabulary);
}
{
int i;
for(i = 0; i < word_counter; ++i){
printf("%s(%d)\n", vocabulary[i].word, vocabulary[i].freq);
}
}
free(vocabulary);
return 0;
}
I am trying to read in a text file, which contains integers, and place them into an array. I will be sorting them once I have the array created. However, I trying to make sure things work as I implement them but I am getting a segmentation fault when I attempt to open a file. I do not understand why.
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>
#define SIZE_T_MAX 16777216
/****** FORWARD DECLARATIONS ******/
void die(const char *message) {
if(errno) {
perror(message);
} else {
printf("ERROR: %s\n", message);
}
exit(1);
}
// ARRAY
typedef struct int_array {
int *array;
size_t length;
size_t capacity;
} int_array;
void int_array_init(int_array *array);
void int_array_free(int_array *array);
void int_array_add(int_array *array, int value);
/****** END OF DECLARATIONS ******/
//
//
/********** MAIN PROGRAM **********/
int main(char argc, char *argv[]) {
// VARIABLES
FILE *data;
int_array numbers;
int_array_init(&numbers);
int i = 0;
char value[10];
// LOAD FILES
printf("Loading files...\n");
data = fopen("list0.txt", "r");
if(data == NULL) die("Failed to load file.");
while(!feof(data) && !ferror(data)) {
fscanf(data, "%s", value);
int_array_add(&numbers, atoi(value));
printf("%d", numbers.array[i]);
i++;
}
// CLEAN UP
int_array_free(&numbers);
fclose(data);
return 0;
}
/*********** END OF MAIN **********/
//
//
/******* ADDITIONAL METHODS *******/
void int_array_init(int_array *array) {
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_free(int_array *array) {
free(array->array);
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_add(int_array *array, int value) {
if (array->length == array-> capacity)
{
int new_capacity;
if (array->capacity == 0) new_capacity = 10;
else new_capacity = array->capacity * 2;
if (new_capacity > array->capacity && new_capacity < SIZE_T_MAX / sizeof(int)) {
int *new_array = realloc(array->array, new_capacity * sizeof(int));
if (new_array != NULL) {
array->array = new_array;
array->capacity = new_capacity;
} else {
die("Out of Memory");
}
} else {
die("Overflow.");
}
}
array->array[array->length] = value;
array->length++;
}
I have corrected and fixed my code. The problem was in the while loop being infinite and corrected with:
while(!feof(data) && !ferror(data))