Order of Arguments in C - c

So, I'm working with some C code. I've defined the following function:
int load_csv(size_t L, size_t W, CSV_DATA csv_data[L][W], char file[])
If i call this function, everything works as it should.
If, however, I change the order of the first two arguments, so that the function is defined as follows:
int load_csv(size_t W, size_t L, CSV_DATA csv_data[L][W], char file[])
I get a segfault when I try to save data to csv_data. Can anyone give any insight into the reasoning why the arguments defined before a struct parameter (csv_data in this case) has to be in the same order?
edit: as requested, here is the entire function:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct{
enum { is_int, is_float, is_char } type;
int ival;
char cval[10];
float fval;
}CSV_DATA;
int load_csv(size_t L, size_t W, CSV_DATA csv_data[L][W], char file[])
{
char buffer[1024] ;
char *record,*line;
int i = 0;
FILE *fstream = fopen("iris.csv","r");
if(fstream == NULL)
{
printf("\n file opening failed ");
return -1 ;
}
while((line=fgets(buffer,sizeof(buffer),fstream))!=NULL)
{
int j = 0;
record = strtok(line,",");
printf("%s", record);
while(record != NULL)
{
csv_data[i][j].type = is_char;
for (int k=0; k < strlen(record); k++){
csv_data[i][j].cval[k] = record[k];//record;
}
j++;
record = strtok(NULL,",");
//printf("%s", record);
}
++i;
}
return 0;
}
edit: here's the calling code. Eventhough..I'm not using L or W anywhere in the called function...
int main(){
int L = 500;
int W = 50;
CSV_DATA csv_data[500][50];
char file[10] = "iris.csv";
load_csv(L ,W , csv_data, file);
return 0;
}

If you swap the order of the parameters in the function definition, then you need to also swap them either in the array parameter declaration or in the function call. IOW, if you change
int load_csv(size_t L, size_t W, CSV_DATA csv_data[L][W], char file[])
to
int load_csv(size_t W, size_t L, CSV_DATA csv_data[L][W], char file[])
then you either need to change the declaration of csv_data as well:
int load_csv(size_t W, size_t L, CSV_DATA csv_data[W][L], char file[])
or you need to change the parameter order in the function call:
load_csv(L, W, csv_data, file);
to
load_csv(W, L, csv_data, file);
Otherwise, the dimensions of csv_data in load_csv will be reversed from the dimensions of csv_data in main, leading to out-of-range array accesses at some point.

The order shouldn't matter - its more likely what you are doing with the values inside the function that has changed - did you change the order of the values where the function is called?

Related

creating a generic array taken from an array of structures

I need to pass to qsort a generic array. That array must be taken from the colons of a file structured like this:
int,string,int,float.
I've created an appropriate struct type but I'm having troubles creating a dinamically allocated array of structures.
here I created an array of pointers to structures
struct *p_structure=malloc(n_records*sizeof(struct record_type*));
and then I have no idea on what to do :(
Any help would be really appreciated, thanks
PS I calculated the n_records in advance
I've created an appropriate struct type but I'm having troubles creating a dinamically allocated array of structures.
Assuming this is your struct:
struct record {
int i1;
char *s;
int i2;
float f;
};
This should be the array declaration:
struct record *array = malloc(sizeof(*array) * n_records);
and then I have no idea on what to do
In case you didn't do it already, you need to parse the file (see Appendix).
Once parsed, you have to define how your array items should compare against each another. In other words, what are the criteria that should be taken into consideration to compare (and of course, sort) your items. Programmatically, you need to provide a function that does that. That function's signature must match the signature of the function that qsort accepts as argument. For example (considering i1 as the comparison criteria):
int compare_record(const void *p1, const void *p2)
{
const struct record *r1 = p1;
const struct record *r2 = p2;
if (r1->i1 > r2->i1)
return 1;
if (r1->i1 < r2->i1)
return -1;
return 0;
}
Now, calling qsort becomes straightforward:
qsort(array, n_records, sizeof(*array), compare_record);
Appendix
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct record {
int i1;
char *s;
int i2;
float f;
};
int compare_record(const void *p1, const void *p2)
{
const struct record *r1 = p1;
const struct record *r2 = p2;
if (r1->i1 > r2->i1)
return 1;
if (r1->i1 < r2->i1)
return -1;
return 0;
}
int main(void)
{
int n_records = 3;
FILE *file = fopen("filename.txt", "r");
if (!file) {
printf("Opening file failed.\n");
exit(EXIT_FAILURE);
}
struct record *array = malloc(sizeof(*array) * n_records);
if (!array) {
printf("An internal error has occurred.\n");
exit(EXIT_FAILURE);
}
int index = 0;
char line[1024]; // Large enough to hold a line?
int i1, i2;
float f;
char s[256];
while (fgets(line, sizeof line, file)) { // PS I calculated the n_records in advance
if (sscanf(line, "%d,%255[^\n,],%d,%f", &i1, s, &i2, &f) != 4) {
// Problematic line...
printf("Problematic line %d...\n", index+1);
}
array[index].i1 = i1;
array[index].s = strdup(s);
array[index].i2 = i2;
array[index].f = f;
++index;
printf("%d | %s | %d | %f\n", i1, s, i2, f);
}
fclose(file);
qsort(array, n_records, sizeof(*array), compare_record);
for (int i = 0; i < n_records; ++i)
printf("%d | %s | %d | %f\n", array[i].i1, array[i].s, array[i].i2, array[i].f);
// Don't forget to free the memory allocated by strdup().
}
It seems that you just created a structure pointer but you don't give it a variable name.
Try this:
struct p_structure *your_var_name =malloc(n_records*sizeof(struct record_type*));
If it won't work, could you provide the code of your structures please ?

C saving game state, reducing passed variables

I've been wondering if there's a way to do a function that saves game state but in transparent way. It's not a question about actual saving (I know how to save to file etc), it's about writing it in a clear, simple and understandable way.
So far I've came to three ideas (remember, I wish it could be a function or some easy thing like savegame()), none is perfect:
Put every variable I want to save into a struct like:
struct state{
int hp;
pos position;
int x;
int y;
...
};
...
if(savegame==1) {
state game;
game.hp=hp;
game.position=position;
game.x=x;
game.y=y;
...
savegame(game);
}
as you can see, it's not looking any good, it takes so many lines to do just a saving: what if I would like to save like 40 variables? What if I want to do saving in like 5-6 places in a code?
Make my function long as snake (this gives a problem with loading it back, so for example I also put a loadgame func):
void savegame(int hp, pos position, int x, int y,...) // too long
{ ... }
void loadgame(int &hp, pos &position, int &x, int &y,...) // too long
{ ... }
...
int main()
{
...
savegame(hp, pos, x, y, ...) // too long
...
loadgame(hp, pos, x, y, ...) // too long
}
again, if it would have 40 variables inside(and i also would like to call savegame or loadgame like 5-6 times), it would take like 4 lines of code each(i just skip an idea to put it in 1 line)
Start my program with struct containing game state, and make all calculations, actually all game on that struct
struct gamestate{
int hp;
pos position;
int x;
int y;
}
...
int main()
{
struct gamestate s;
s.x++;
...
}
but this leads to a problem where everytime I make calculations I have to add this 's' at beggining.
Conclusion:
My idea was to maybe change second option just to reduce every call of savegame(...); to simple savegame();, is there a way to do it? Without define?
Here is a dynamic way to do something similar to what you describe in your 1st option, i.e. track a game state using pointer to struct but that also stores and recovers that data to and from a binary file...
The following .c and .h files illustrate the idea that you can use a compound struct, i.e. one containing several other structs, that at any one time contain all of the values representing states in your program. This is very easily passed via a function(s) with very few arguments (prototyped eg. as char *GetState(state *in, const char *filespec); and char *SetState(state *out, const char *filespec); ) which in turn would write or read the contents of the struct into/out of a binary buffer. I have used this method to store and retrieve multiple sets of state data within files.
Note, the structs have random fields that of course you will modify as needed, but the idea is that you can pass a single pointer value that points to all the state data, in every function where state date is updated, or needs to be stored.
so_SaveGameState.c
#include <so_SaveGameState.h>
unsigned char *pByteA;
GAME_STATE game = {{{"jim", "C:\\ico1.ico", {10, 120, 3}}, {"joe", "C:\\ico2.ico", {80, 10, -5}},{"larry", "C:\\ico3.ico", {15, -45, -45}},{"sue", "C:\\ico4.ico", {-100, -45, 45}}}, ENVR_3};
GAME_STATE *pGame = NULL;
int main(void)
{
pGame = &game;//point to populated memory
printf("Player 3 position\nx = %d\ny = %d\nz = %d\n", game.plyr[2].pos.x, game.plyr[2].pos.y, game.plyr[2].pos.z);
//example function that changes game state
UpdatePlayerPosition(&pGame, 2);
printf("Player 3 position\nx = %d\ny = %d\nz = %d\n", game.plyr[2].pos.x, game.plyr[2].pos.y, game.plyr[2].pos.z);
UpdatePlayerPosition(&pGame, 2);
printf("Player 3 position\nx = %d\ny = %d\nz = %d\n", game.plyr[2].pos.x, game.plyr[2].pos.y, game.plyr[2].pos.z);
UpdatePlayerPosition(&pGame, 2);
printf("Player 3 position\nx = %d\ny = %d\nz = %d\n", game.plyr[2].pos.x, game.plyr[2].pos.y, game.plyr[2].pos.z);
//prepare an instance of game state for storeing
(const GAME_STATE *)pByteA = &game;
int len1 = sizeof(game);
BOOL status = storeState("C:\\tempextract\\binFileStruct.bin", pByteA, len1);
//recover a stored state
unsigned char *buf = recoverState("C:\\tempextract\\binFileStruct.bin");
GAME_STATE *game_2 = (GAME_STATE *)buf;
free(game_2);
return 0;
}
unsigned char * recoverState(const char *filespec)
{
size_t sz = 0;
int n = 0;
unsigned char *binBuf = NULL;
FILE *fp = fopen(filespec, "rb");
if(fp)
{
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
fseek(fp, 0L, SEEK_SET);
rewind(fp);
binBuf = calloc(sz, sizeof(*binBuf));
n = fread(binBuf, sizeof(unsigned char), sz, fp);
fclose(fp);
}
if(n == sz)
{
return binBuf;
}
else
{
return NULL;
}
}
int storeState(const char *filespec, const unsigned char *buf, size_t sz)
{
int count = 0;
FILE *fp = fopen(filespec, "wb");
if(fp)
{
count = fwrite(buf, sizeof(unsigned char), sz, fp);
fclose(fp);
}
return (count == sz) ? 1 : 0;
}
void UpdatePlayerPosition(GAME_STATE **game, int player)
{
static int x=0, y=0, z=0;
static BOOL toggle = TRUE;
toggle = (toggle == 1) ? -1 : 1;
srand(clock());
//using fake assignment here
//i.e. you would have other criteria to set actual position
x += toggle * rand()%300;
y += toggle * rand()%300;
z += toggle * rand()%300;
(*game)->plyr[player].pos.x = x;
(*game)->plyr[player].pos.y = y;
(*game)->plyr[player].pos.y = z;
}
so_StoreGameState.h
typedef enum {//environment
ENVR_1, //bad weather
ENVR_2, //hill
ENVR_3, //pit
ENVR_4, //angry birds
ENVR_5, //enemy guard
MAX_OBST
}ENVR_TYPE;
typedef struct {
int x;
int y;
int z;
}POS;
typedef struct {
ENVR_TYPE envir;
//...
}ENVIR;
typedef struct {
char name[20];
char iconFile[260];
POS pos;
//...
}PLAYER;
typedef struct {
PLAYER plyr[4];
ENVIR env;
//...
}GAME_STATE;
extern GAME_STATE game;
unsigned char * recoverState(const char *filespec);
int storeState(const char *filespec, const unsigned char *buf, size_t sz);

C: Check if array includes consecutive elements that are equal

Yesterday I had a test on C where I coudn't figure out the last question:
We were given two arrays of two types of arrays: arrays including consecutive elements that are equal(eg: {"stack","heap","heap"}) and arrays of where no consecutive elements where equal (eg: {1,2,3,4,5,6,7,8,9}).
We were then asked to find one function that returned 1 or 0 if the given array contained doubles or not. So this function had to work with both integer arrays and char * arrays.
This is what I came up with today (but it keeps giving the wrong answer and crashing afterwards or a segmentation fault when comparing the strings)
Edit: correct code (thanks to #BLUEPIXY !)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int contains_dup(void *array, size_t size, size_t sizeoftype, int (*cmp)(const void*, const void*)){
//array != NULL, size != 0
char *obj = array;
size_t i;
for(i = 0; i < size-1; ++i){
if(cmp(obj + sizeoftype * i, obj + sizeoftype * (i+1)))
return 1;
}
return 0;
}
int eqi(const void *a, const void *b){
int x = *(const int *)a;
int y = *(const int *)b;
return x == y;
}
int eqs(const void *a, const void *b){
return strcmp(a, b) == 0;
}
#define TEST(name, cmp)\
do{\
int test;\
puts(#name ":");\
test = contains_dup(name, sizeof(name)/sizeof(*name), sizeof(*name), cmp);\
test ? puts("doubles? Yes\n") : puts("doubles? No\n");\
}while(0)\
/**/
int main(void){
int ints_yes[] = {0,1,2,2,2,3,4,4,5};
int ints_no[] = {0,1,2,3,4,5,6,7,8};
char *strings_yes[]={"heap","stack","stack","overflow"};
char *strings_no[] ={"heap","stack","heap","stack","overflow"};
puts("test:");
TEST(ints_yes, eqi);
TEST(ints_no, eqi);
TEST(strings_yes, eqs);
TEST(strings_no, eqs);
return 0;
}
Wrong old code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int array_contains_doubles(void ** array, int size, int sizeoftype){
int i;
char **out =(char**) malloc(size * sizeof(char*));
for(i=0;i<size;i++){ //trying to convert the array of ints to an
out[i] = array+i*sizeoftype; //array of char * eg: {1,2} ->{"1","2"}
// *out[i] +='a';
printf("%c\n",*out[i]);
}
out[i]= NULL;
while(*(out+1)!=NULL){
if(strcmp(*out,*(out++))==0){ //<- where i get the segmentation error
return 1;
}
}
return 0;
}
int main(void){
int i;
int ints_yes[] = {0,1,2,2,2,3,4,4,5};
int ints_no[]={0,1,2,3,4,5,6,7,8};
char * strings_yes[]={"heap","stack","stack","overflow"};
char * strings_no[]={"heap","stack","heap","stack","overflow"};
int test = array_contains_doubles((void **) ints_no,
sizeof(ints_no)/sizeof(ints_no[0]), sizeof(int));
(test) ? (printf("doubles? Yes")) : (printf("doubles? No"));
}
Sorry for any spelling mistakes, english is not my native language.
What your teacher is likely fishing for, is for you to implement a "functor" similar to the function pointer passed to bsearch (study this function). Something along the lines of this:
typedef int comp_func_t (const void*, const void*);
bool equal (const void* obj1, const void* obj2, comp_func_t* comp)
{
return comp(obj1, obj2)==0;
}
You call equal from your application with a pointer to the objects to compare, no matter what kind of objects they are. The function pointer specifies how objects of this type should be compared. You then implement the comparison functions for each type:
int comp_int (const void* obj1, const void* obj2)
{
int a = *(const int*)obj1;
int b = *(const int*)obj2;
if(a < b)
{
return -1;
}
else if(a > b)
{
return 1;
}
else // a == b
{
return 0;
}
}
int comp_str (const void* obj1, const void* obj2)
{
...
}
Typical use could be:
int x;
int y;
...
if(equal(&x, &y, comp_int))
{
...
}
Now this only compares two objects, so you'll have to expand this for an array by 1) sorting the array and 2) calling it for every two adjacent items in the sorted array, to find out if any are equal.
The above is the old, "de facto standard" way to implement type-specific behavior in C. In newer versions of the language, more elegant ways are available through the _Generic keyword, but this would probably not be addressed on a beginner-level class.

First use of headers in c and really not understanding it well

I using first time the HEADERS in c so I'm not understanding it well.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "kibe.h"
int main()
{
int a[5],n,i;
beolvas(a,n,"be.txt");
kiir(a,n);
return 0;
}
kibe.h
#ifndef KIBE_H_INCLUDED
#define KIBE_H_INCLUDED
void beolvas(int*, int, const char *);
void kiir(int*, int);
#endif // KIBE_H_INCLUDED
kibe.c
#include <stdio.h>
#include <stdlib.h>
void beolvas(int *a,int n,const char * file)
{
int i;
FILE * fin;
fin = fopen("be.txt", "rt");
fscanf(fin,"%i",&n);
a = (int*)malloc(n*sizeof(int));
for(i = 0; i < n; ++i){
fscanf(fin,"%i",&a[i]);
}
free(a);
}
void kiir(int *a,int n)
{
int i;
for(i = 0; i < n; ++i){
printf("%i ",a[i]);
}
}
The problem is that I get memory garbage every time and the file contains five numbers which must be read and written to monitor. If I write the void kiir is code to void beolvas function it works well.
You allocate dynamic memory in your function beolvas but you never pass it out of the function. Your parameters a and n have to be output parameters, so you have to change your function signature. Apart form this use fclos to close the file. Adapt your code like this:
kibe.c
void beolvas( int **a, int *n, const char * file )
// ^^ ^ output paramters a and n
{
FILE * fin;
fin = fopen("be.txt", "rt");
fscanf( fin, "%i", n ); // read number of elements
// ( n is a pointer to an int )
*a = malloc( *n * sizeof(int) ); // allocate memors
for ( int i = 0; i < n; ++i)
{
fscanf(fin,"%i",(*a)+i); // read one element
// ( *a is the pointer to the dynamic memory,
// so (*a)+i is a pointer to (*a)[i] )
}
fclose(fin);
}
kibe.h
void beolvas( int**, int* , const char *);
main.c
int main()
{
int a* = NULL;
int n = 0;
beolvas( &a, &n,"be.txt");
// ^ ^
kiir( a, n );
free(a); // free the memory which was allocated inside function beolvas
return 0;
}

function that initiailzes a struct with a char - explain my warning?

Does anyone know why the code below does not work with chars? It works with ints but when I want to use char to initialize structure it fails and gives a warning like:
warning: assignment makes integer from pointer without a cast
I don't know what this warning means.
#include <stdio.h>
#include <stdlib.h>
struct complex {
int re;
int im;
char name;
};
struct complex initialize (int k, int l, char nazwa)
{
struct complex x;
x.re = k;
x.im = l;
x.name= nazwa;
return x;
}
int main ()
{
struct complex e;
struct complex f;
int a;
int b;
char o;
int c;
int d;
char p;
a=5;
b=6;
o="t";
e = initialize (a, b, o);
c=8;
d=3;
p="u";
f=initialize (c, d, p);
printf("c1 = (%d,%d)\nc2 = (%d,%d)\n name 1=%s name 2=%s\n", e.re , e.im, f.re, f.im, e.name, f.name);
return 0;
}
"u" is not a char. it is a string. a char array. you want 'u' instead. But then you will have only one-character names, and you will need to replace the %s in printf with %c.
Unless you really want a string, and if so change your char in the struct to be const char*. The same goes the function parameter:
struct complex {
int re;
int im;
const char* name;
};
struct complex initialize (int k, int l, const char* nazwa) {
...
}
const char* o;
const char* p;
Note that you can initialize variables, and structs. your code can be like this:
void print_complex(int n, struct complex c) {
printf("c %d = (%d,%d)\n", n, c.re , c.im);
printf("name=%s\n", c.name);
}
int main () {
struct complex e = { 5, 6, "t" };
struct complex f = { 8, 3, "u" };
print_complex(1, e);
print_complex(2, f);
return 0;
}

Resources