Passing Variables in C - c

I have a C program where I'm reading in from a file and then trying to print it to test it at the moment. The thing i'm having issues is that my const in MAX = 40 and its printing that amount of times. I've tried passing a reference to jobcount in the function but I get an error when I add * after int and an & before jobcount when passing it. I appreciate the help, its always quality input on all issues!
#include <stdio.h>
struct record{
char name[1];
int arrival_time;
int job_length;
int job_priority;
};
const int MAX = 40;
void fileinput(struct record jobs[MAX], int jobcount);
void output(struct record jobs[MAX], int jobcount);
int main(void)
{
struct record jobs[MAX];
int jobcount;
fileinput(jobs,jobcount);
output(jobs,jobcount);
return(0);
}
void fileinput(struct record jobs[MAX], int jobcount){
jobcount = 0;
FILE *f = fopen("data.dat","r");
while(fscanf(f, "%s %d %d %d", jobs[jobcount].name, &jobs[jobcount].arrival_time, &jobs[jobcount].job_length, &jobs[jobcount].job_priority) != EOF)
{
jobcount++;
printf("READ IN TEST \n");
}
}
void output(struct record jobs[MAX], int jobcount){
int j = 0;
for(j = 0;j < jobcount; j++)
{
printf("%s %d %d %d\n", jobs[j].name, jobs[j].arrival_time, jobs[j].job_length, jobs[j].job_priority);
printf("FOR LOOP TEST \n");
}
}
data.dat looks like this
A1 3 3 3
B1 4 4 4
C1 5 5 5

You should not get an error. Probably you might have changed in the forward declaration alone and forgot to change at the definition.
void fileinput(struct record jobs[MAX], int* jobcount);
fileinput(jobs,&jobcount);
And definition -
void fileinput(struct record jobs[MAX], int* jobcount) {
// ....
}
Since jobcount is a pointer, you need to dereference first to modify/access the value it is pointing at. You need to post the exact error message for further help though.

You would probably do best to revise fileinput() to return the job count:
int fileinput(struct record jobs[MAX])
{
int jobcount = 0;
...
return jobcount;
}
And then, in main():
int main(void)
{
struct record jobs[MAX];
int jobcount = fileinput(jobs);
...
return 0;
}
The main alternative is to pass a pointer to jobcount to the fileinput() function. This would perhaps be better if you also returned a status (all OK, too many entries in the data, bogus data, etc). Your function would still return a value, but it would be the error indication, and the job count would be returned via the pointer.
A third (gruesome and not recommended) alternative is to use a global variable (or file static variable) for jobcount.
For a generalized input function, you should pass the size of the array explicitly, rather than assuming it is MAX:
int fileinput(struct record jobs[], size_t maxjobs);
int jobcount = fileinput(jobs, MAX);
You'd write the code to ensure that you do not exceed the specified number of job records.

You CAN get "jobcount" from fileinput() withing a "return", if you want to. You just need "&", passing in a pointer to "jobcount":
...
const int MAX = 40;
void fileinput(struct record jobs[MAX], int * jobcount);
...
int main(void)
{
struct record jobs[MAX];
int jobcount=-1;
fileinput(jobs,&jobcount);
output(jobs,jobcount);
return(0);
}
void fileinput(struct record jobs[MAX], int * jobcount){
*jobcount = 0;
FILE *f = fopen("data.dat","r");
while(
(fscanf(f, "%s %d %d %d", jobs[jobcount].name, &jobs[jobcount].arrival_time,
&jobs[jobcount].job_length, &jobs[jobcount].job_priority) != EOF) &&
(*jobcount < MAX) )
{
*jobcount++;
printf("READ IN TEST \n");
}
...

Related

C: Using strcpy to transfer one struct element to an array

Okay, so we're supposed to prompt a user to enter 25000 lines of text.
Each line contains three integers each. We are then to pass the third integer in that line to another struct, and connect each integer until you have 25000 interconnected integers.
Here's what I've tried:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct graph{
int begin;
int end;
int cost;
} PathEdge;
int comp_fcn(const void *a, const void *b) {
return ((PathEdge *) a)->cost - ((PathEdge *) b)->cost;
}
int main(void)
{
int nlines,i;
char r;
int ecost,ebegin,eend;
scanf("%d",&nlines);
PathEdge edges[nlines+1];
for(i=0;i<nlines;i++)
{
scanf("%d, %d, %dn",&ebegin, &eend, &ecost);
edges[i].begin = ebegin;
edges[i].end = eend;
edges[i].cost = ecost;
struct town
{
struct town *north;
int name[25000];
};
struct town *root, *current;
root = malloc(sizeof(struct town));
root->north = NULL;
strcpy (root->name,ecost);
current = malloc(sizeof(struct town));
current->north = root;
strcpy (current->name,ecost);
}
printf("Please enter a node that you want to examine. If you want to exit, please press 'X'.n");
scanf("%c",&r);
switch(r)
{
case 'X':
case 'x':
printf("You entered a wrong value. Gomen. Try againn.");
break;
default:
if((0<r)&&(r<25000))
{
printf("You have accessed node %dn",r);
printf("Its neighboring nodes are %dn",edges[r].cost);
printf("Its neighboring nodes are %dn",edges[i].cost);
}
else
{
printf("Invalid input again. Please do try again. Thanksn");
}
break;
}
return 0;
}
And there are warnings...
"passing argument 1 of strcpy from incompatible pointer type"
"passing argument 2 of strcpy makes pointer from integer without a cast"
expected char*__ restrict __ but argument is of type 'int'
plus when I inputted that 25000 lines of text, segmentation fault happens. Please help. Thank you!
strcpy is for copying strings (i.e. zero terminated byte char "arrays"), you maybe should use memcpy instead.
Or if you just want to assign a single integer to one element in the array, use plain assignment:
current->name[someIndex] = ecost;
Or, maybe you intend that thename member should be a string? Then you should be using an array of characters and not integers. And you need to convert integer values to strings, using e.g. sprintf:
sprintf(current->name, "%d", ecost);
you can convert the integer to string using itoa and copy the string into root->name.
char str[20];
itoa(ecost, str, 10);
strcpy(root->name, str);
You did not state your exact issue so I am assuming you are overwhelmed and in that case you should try partitioning your implementation into functions so that you can work on isolated problems instead of a web of interconnected problems.
Here is one example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct graph {
int begin;
int end;
int cost;
} PathEdge;
const char * GenerateInput()
{
static char local[2000];
static int last = 0;
int a, b, c;
a = last++;
b = last++;
c = last++;
sprintf_s(local, 2000, "%i %i %i", a, b, c);
return local;
}
void PathEdgeInitializeFromString(PathEdge * edge, const char * str)
{
sscanf_s(str, "%d %d %dn", &edge->begin, &edge->cost, &edge->end);
}
void QueryAndPrint(PathEdge * edges, int edges_n)
{
printf("Enter a number from 1 to %i: ", edges_n);
int index = 0;
scanf_s("%i", &index);
--index;
if (index < 0 || !(index < (edges_n)))
printf("Error");
else
printf("%i, %i, %i\n", edges[index].begin, edges[index].cost, edges[index].end);
}
int main() {
PathEdge edges[25000];
for (int i = 0; i < 25000; ++i)
{
const char * line = GenerateInput();
PathEdgeInitializeFromString(edges + i, line);
}
QueryAndPrint(edges, 25000);
return 0;
}

Hash Table in C (find the frequency of every word)

I want to create a hash table for an exercise I have to send in my University.
The program will open a number of files, break each file's content to <<words>> (tokens) and it will save each <<word>> in a hash table with the frequency of each <<word>>.
In case the word is already in the hash table , the program will increase the word's frequency.
At the end the program will print the words and it's frequencies accordingly.
Also the frequencies should be printed from the highest word frequency to the lowest.
The comparison of the <<words>> will ignore upper and lower case letters.
For example if a file contains : one two three four Two Three Four THREE FOUR FoUr
It should print:
four 4
three 3
two 2
one 1
The professor gave us a template that we should complete but I'm really confused on what to do with the insert_ht() and clear_ht() functions as well as the compare one.
Here is the code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024
/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };
link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */
unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );
void Process(FILE *fp);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
for (i=1; i < argc; i++)
{
fp = fopen(argv[i],"r");
if (NULL == fp)
{
fprintf(stderr,"Problem opening file: %s\n",argv[i]);
continue;
}
Process(fp);
fclose(fp);
}
print_ht();
clear_ht();
return 0;
}
void Process(FILE *fp)
{
const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";
char line[MAX_LINE_SIZ];
char *s;
while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
{
for (s=strtok(line,seperators); s; s=strtok(NULL,seperators))
insert_ht(s);
}
}
/* Hash Function */
unsigned int hash(char *tok)
{
unsigned int hv = 0;
while (*tok)
hv = (hv << 4) | toupper(*tok++);
return hv % HTABLE_SIZ;
}
void insert_ht(char *token)
{
……………………………………………
}
void clear_ht()
{
……………………………………………
}
int compare(const void *elem1, const void *elem2)
{
……………………………………………
}
void print_ht()
{
int i, j=0;
link l, *vector = (link*) malloc(sizeof(link)*size);
for (i=0; i < HTABLE_SIZ; i++)
for (l=htable[i]; l; l=l->next)
vector[j++] = l;
qsort(vector,size,sizeof(link),compare);
for (i=0; i < size; i++)
printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
free(vector);
}
I'll answer you in a new post because it's hard to be exhaustive in comments.
1. Malloc
Why would I need to use malloc then ? Shouldn't i write directly to the htable? (on the insert_ht() funtion)
You need to use malloc because you declare a char pointer in struct (char *token). The thing is that you never initialize the pointer to anything, and as far you don't know the size of the token, you need to malloc every token. But, as you use strdup(token), you don't need to malloc token because strdup does. So don't forget to free every token in order to avoid memory leaks.
2. Segfault
I can't test you code, but it seems like the following line causes the segmentation fault :
list = htable[hashval]->token
Indeed, you try to access token while htable[hashval] is NULL, and to assign a char * to a link type (list).
You need to loop with this :
for(list = htable[hashval]; list != NULL; list = list->next) { ... }
3. Notes
if (x=1) should be if(x==1).
Don't malloc new_list if you don't need to.
Because new_list if used when htable[hashval] is NULL, new_list->next = htable[hashval]; will set new_list->next to NULL.
You should use the -Wall option in gcc (for warnings) and you may use valgrind to understand your segmentation faults. In this case, use gcc with debug mode (-g).
Double and Final edit : Ι found the solution. Apparently for some reason my compare function was wrong.
I still haven't figured out why but here is the correct one, hopefully someone else will find this post helpful!
int compare(const void *elem1, const void *elem2)
{
return (*(link*)elem2)->freq - (*(link*)elem1)->freq;
}
Edit: deleted old answer . Found the correct way I think but I have another problem right now.
The compare function doesn't work correctly. My printf is fine but it doesnt sort them with the frequiencies. I want them to be sorted from the highest to lowest .
In this example: the file contains -> one two three four Two Three Four THREE FOUR FoUr
And I get:
two 2
one 1
four 4
three 3
While I should be getting :
four 4
three 3
two 2
one 1
Here is the code. Feel free to help!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024
/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };
link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */
unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );
void Process(FILE *fp);
int main(int argc, char *argv[])
{
int i;
FILE *fp;
printf("prin tin for \n");
for (i=1; i < argc; i++)
{
printf("prin tin fopen \n");
fp = fopen(argv[i],"r");
if (NULL == fp)
{
fprintf(stderr,"Problem opening file: %s\n",argv[i]);
continue;
}
printf("prin tin process \n");
Process(fp);
fclose(fp);
}
print_ht();
//clear_ht();
return 0;
}
void Process(FILE *fp)
{
const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";
char line[MAX_LINE_SIZ];
char *s;
while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
{
for (s=strtok(line,seperators); s; s=strtok(NULL,seperators)){
printf("prin tin insert %s \n",s);
insert_ht(s);
}
}
}
/* Hash Function */
unsigned int hash(char *tok)
{
printf("bike stin hash \n");
unsigned int hv = 0;
while (*tok)
hv = (hv << 4) | toupper(*tok++);
printf("VGAINEIIIIIIIIIIIIII %d \n",hv);
return hv % HTABLE_SIZ;
}
void insert_ht(char *token)
{
printf("bike stin insert %s \n",token);
unsigned int hashval = hash(token);
if (htable[hashval]==NULL){
printf("mesa stin prwti if %u %s \n",hashval,token);
//token = strdup(token);
htable[hashval] = malloc(sizeof(token));
htable[hashval]->token = token ;
htable[hashval]->freq = 1;
size++;
}else {
htable[hashval]->freq++;
}
printf("ta evale epitixws \n");
}
int compare(const void *elem1, const void *elem2)
{
const struct node *p1 = elem1;
const struct node *p2 = elem2;
if ( p1->freq < p2->freq)
return -1;
else if (p1->freq > p2->freq)
return 1;
else
return 0;
}
void print_ht()
{
int i, j=0;
link l, *vector = (link*) malloc(sizeof(link)*size);
for (i=0; i < HTABLE_SIZ; i++)
for (l=htable[i]; l; l=l->next)
vector[j++] = l;
qsort(vector,size,sizeof(link),compare);
for (i=0; i < size; i++)
printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
free(vector);
}
Sorry for my bad english.
I think that :
insert(char *token) takes a word of the file and puts into the hash table. In brief, if the word exists in the hash table, you just have to increment its frequencie. Otherwise, you need to create another node and put the frequencie to 1, then ad it to the array. At the end, you will have one entry for each unique word.
compare(const void *elem1, const void *elem2) will be used by qsort. It returns 0 if elem1 = elem2, a negative number if elem1 < elem2 and a number > 0 if elem1 > elem2. By passing compare to qsort, you allow qsort to sort you array according to your own criteria.
clear_ht() may set all the values of the array to NULL, in order to restart another count ?

Struct arrays in C

Hi I'm having trouble trying to initializing each element of the struct array. When I try and assign the value ZERO to both 'bSize' and 'msgs', it doesn't work as it errors out when i get to malloc. In the printf statement it prints a -1852803823 number. Excuse the messy code as i'm playing around trying to figure it out.
struct message{
int *data;
int bSize;
int msgs;
};
int main(int argc, char *argv[]) {
.....
}
void getSchedFile (FILE *file, int **schd) {
struct message sMsg[nodeCount];
const int pakSize = 6;
// Iniitialise message buffer
for (int i=0; i<nodeCount; i++){
sMsg[i].bSize = 0;
sMsg[i].msgs = 0;
printf("bSize %d\n",sMsg[i].bSize);
}
/* Get the number of bytes */
fseek(file, 0L, SEEK_SET);
int time;
while((fscanf(file, "%d", &time)) != EOF){
int src;
fscanf(file, "%d", &src); // get source node id
// These are here for easier reading code
int aPos = sMsg[src].bSize;
int nMsg = sMsg[src].msgs;
printf("size %d\n", sMsg[src].bSize);
if (sMsg[src].bSize==0){
sMsg[src].data = malloc( pakSize * sizeof(int));
}else{
sMsg[src].data = realloc(sMsg[src].data, (aPos+pakSize)*sizeof(int));
}
Where is the nodeCount value coming from? Is it a global variable? You should be very careful with global variables, and avoid using them if possible.
Pass the nodeCount in the method parameter and as Charlie mentioned, check it for > 0

How to pass struct array into a function and correctly store value in it?

I would like to read a file that has the sample number, values and status(1.1, 23,0). I used a Struct to hold that information. I will pass the function struct array and the file location.
#include <stdio.h>
struct Data_point
{
long sampleNumber;
double value;
int status;
};
int filldata(struct Data_point *a, const char *filelocation)
{
FILE *f;
if((f=fopen(filelocation,"r"))==NULL)
{
printf("You cannot open");
}
fscanf(f, "%ld%lf%d", a.sampleNumber, a.value, a.status);
}
int main(void)
{
struct Data_point data[10];
filldata(data, "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
return 0;
}
But, I got an error saying, "request for member not a structure"...
One problem is that the filldata() is taking a pointer argument. So you use -> to address members not ".". So a.sampleNumber should be a->sampleNumber for example.
Another issue is that filldata() is reading in a single struct, but you are passing it the pointer to the top of the array, which is synonymous with &(data[0]). So this function will just overwrite that first element if you call it repeatedly (which you didn't). If you call it in a loop you will need to pass it in pointers to the individual array members:
for(int i = 0; i < 10; ++i){
filldata(&(data[i]), "/home/alexchan/IntrotoC/rec11/dataPoints.txt");
}
You could actually use data + i as the first arg instead of &(data[i]) but I like the latter as I find it more readable.
struct Data_point *a is your function arugument and you are passing data which is a array. So basically you are trying to acess members from a array which is not a struct.
May be
for( int i=0; i<10;++i)
filldata(data[i],.....)
and
int filldata( struct Data_point a,...) //as you are using a.
fscanf requires a pointer-to-data for each passed argument. Use the AddressOf operator & to get a reference to each struct member:
int filldata(const char *filelocation, struct Data_point *a, int nElements)
{
int n = 0;
FILE *f = fopen(filelocation, "r");
if(f)
{
while (fscanf(f, "(%ld,%lf,%d)", &(a[n].sampleNumber), &(a[n].value), &(a[n].status)) == 3 && n < nElements)
n++;
fclose(f);
}
else { printf("Unable to open '%s'\n", filelocation); }
return n;
}
Now, this function is slightly different to yours. You need to tell it how long the array you're passing in as the "a" parameter is. It will return the number of successfully filled entries.
i.e
int main(int argc, char **argv)
{
struct Data_point data[10];
int n = filldata("C:\\Users\\254288b\\temp.txt", data, sizeof(data) / sizeof(struct Data_point));
printf("%d Data_point's were filled successfully.\n\n", n);
for(int i = 0; i < n; i++)
{
printf("Sample Number: %ld\n", data[i].sampleNumber);
printf("Value: %lf\n", data[i].value);
printf("Status: %d\n", data[i].status);
printf("----------------------------\n");
}
return 0;
}
Do note, my pattern for fscanf expects your file to be like:
(100,1.1,10)(200,2.2,20)(300,3.3,30)(400,4.4,40)
Each set is enclosed in parenthesis.

C - Call a function

I want to get a value from a function in other function i think i have to call a function in other function, then call it on main, but how?
void funcA(PEOPLE people[], int *total)
{
FILE *fp;
char line[100];
fp = fopen("example.txt", "r");
if (fp == NULL) {
exit(1);
}
else {
fgets(line, 100, fp); //get a number from the txt
total = atoi(line); //convert to int
}
}
void funcB(PEOPLE people[], int *total)
{
int i;
for (i = 0; i < total; i++) {
printf("%s\n", people[i].name);
}
funcA(people, &total);
}
void main()
{
PEOPLE people[100];
int *total;
funcB(people, &total);
}
What i'm doing wrong? I need the value from total to do cicle for;
First, you should call funcA from funcB like this:
funcA(people, total);
Then, if I understand you correctly, you want to return a value from your function(s). You can do it like this:
int funcA(PEOPLE people[], int *total){
int ret;
// set ret to desired value
return ret;
}
...
int value = funcA(people, total);
After sorting this out, you need to initialize your variables correctly, sort out the naming discrepancies (linha vs line, PEOPLE vs PERSON) and all other issues noted by others.
There are numerous problems here (total is a pointer, for loop on the pointer, never initialized to anything, etc etc).
To answer your question, functions have return types:
int foo(void) {
return 3;
}
int main(int argc, char**argv) {
printf("Foo returned %d\n", foo());
return 0;
}
In this case foo returns int. You return values with the return keyword.
You can also return data in pointers:
void foo(int* c) {
*c = 3;
}
int main(int argc, char**argv) {
int h;
foo(&h);
printf("Foo returned %d\n", h);
return 0;
}
This is helpful if you have multiple values to return.
Oh boy !
First what You are doing right or at least it seems so. You are drawing attention and get points for upvotes, despite the fact, that the code looks like typed in directly to the editor box on the Stackoverflow and never checked with any compiler. Good job :)
Now what's wrong. The list is long but some tips
void main()
{
PERSON person[100];
int *total;
funcB(people, &total);
}
void funcB(PEOPLE people[], int *total);
It would be nice if You showed us the definitions of (probably) structs PEOPLE and PERSON.
In the code we can see, there is no definition of people - the variable you pass to funcB.
You define a pointer to int - total and don't initialize it. Then You pass an address of that pointer to funcB which takes int* not int** as a second argument. Those types are not compatible.
void funcB(PEOPLE people[], int *total)
{
int i;
for (i = 0; i < total; i++) {
printf("%s\n", people[i].name);
}
funcA(people, &total);
}
void funcA(PEOPLE people[], int *total)
You use a pointer in the loop condition instead of the value pointed too. There is no value, because You didn't initialize the pointer in main, but here You have incompatible types in the condition. You pass an address of the pointer to funcA instead of the pointer, like in main.
void funcA(PEOPLE people[], int *total)
{
FILE *fp;
char line[100];
fp = fopen("example.txt", "r");
if (fp == NULL) {
exit(1);
}
else {
fgets(line, 100, fp); //get a number from the txt
total = atoi(linha); //convert to int
}
}
You use an undefined symbol 'linha' - I guess it's a misspelling of 'line'. Then You assign an int to a pointer instead of an int pointed to by that pointer.
Check these:
exit() function exited from your program, not only from function. You can use return; to return from the function.
total is not initialized when you use that. Use funcA(people, &total); line before the for loop in your function funcB.

Resources