I am required to organize the following c code into header (s) and c file (s). However, im unable to do so myself.
The code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 256
#define PROGRAMMES_SIZE 2
#define DELIMETER ","
struct programme
{
char name[32];
char code[8];
int credits;
};
struct programme parseProgramme(char *);
struct programme createProgramme(char[], char[], int);
void printProgramme(struct programme);
void updateProgrammeName(struct programme *, char[]);
int main()
{
char buffer[BUFFER_SIZE];
struct programme programmes[PROGRAMMES_SIZE];
FILE *input = fopen("input", "r");
if (input == NULL)
exit(1);
int i;
for (i = 0; i < PROGRAMMES_SIZE; i++)
{
fgets(buffer, BUFFER_SIZE, input);
programmes[i] = parseProgramme(buffer);
}
for (i = 0; i < PROGRAMMES_SIZE; i++)
printProgramme(programmes[i]);
fclose(input);
return 0;
}
struct programme parseProgramme(char *buffer)
{
char name[32];
char code[8];
int credits;
// parse name
strcpy(name, strtok(buffer, DELIMETER));
// parse code
strcpy(code, strtok(NULL, DELIMETER));
// parse credits
credits = atoi(strtok(NULL, DELIMETER));
return createProgramme(name, code, credits);
}
struct programme createProgramme(char name[], char code[], int credits)
{
struct programme programme;
strcpy(programme.name, name);
strcpy(programme.code, code);
programme.credits = credits;
return programme;
}
void printProgramme(struct programme programme)
{
puts(programme.name);
puts(programme.code);
printf("%d\n", programme.credits);
}
void updateProgrammeName(struct programme *programme, char name[])
{
strcpy(programme->name, name);
}
Please be noted that its not required to update any of the following definitions or implementations of the code listed above, stated by my collage professor. Just to organize them accordingly, any help is apricated!.
There is no strict need to create a separate header file here, because there is no code re-use.
However, if some of the code were to be reused in other files, then it would start to make sense. So let's say we want to move some functionality to a library.
Then it would make sense to split up the functions to a separate file, and create a header file which would also be roughly representing the API.
So let's skip some code and look at main.c:
int main()
{
char buffer[BUFFER_SIZE];
struct programme programmes[PROGRAMMES_SIZE];
FILE *input = fopen("input", "r");
if (input == NULL)
exit(1);
int i;
for (i = 0; i < PROGRAMMES_SIZE; i++)
{
fgets(buffer, BUFFER_SIZE, input);
programmes[i] = parseProgramme(buffer);
}
for (i = 0; i < PROGRAMMES_SIZE; i++)
printProgramme(programmes[i]);
fclose(input);
return 0;
}
And obviously the functions would be in e.g. program.c:
struct programme parseProgramme(char *buffer)
{
char name[32];
char code[8];
int credits;
// parse name
strcpy(name, strtok(buffer, DELIMETER));
// parse code
strcpy(code, strtok(NULL, DELIMETER));
// parse credits
credits = atoi(strtok(NULL, DELIMETER));
return createProgramme(name, code, credits);
}
struct programme createProgramme(char name[], char code[], int credits)
{
struct programme programme;
strcpy(programme.name, name);
strcpy(programme.code, code);
programme.credits = credits;
return programme;
}
void printProgramme(struct programme programme)
{
puts(programme.name);
puts(programme.code);
printf("%d\n", programme.credits);
}
void updateProgrammeName(struct programme *programme, char name[])
{
strcpy(programme->name, name);
}
Now we can easily see, that PROGRAMMES_SIZE and BUFFER_SIZE are not used in the functions, and should be defined in main.c.
On the other hand, DELIMETER is only used in the functions, so it should be defined at the top in program.c.
We can move the struct and function definitions to program.h. It's good practice to prevent recursive inclusion, we could use some simple ifndef for that:
#ifndef PROGRAM_H
#define PROGRAM_H
struct programme
{
char name[32];
char code[8];
int credits;
};
struct programme parseProgramme(char *);
struct programme createProgramme(char[], char[], int);
void printProgramme(struct programme);
void updateProgrammeName(struct programme *, char[]);
#endif /* PROGRAM_H */
Finally, you should look which standard library functions are used in either .c file and add the necessary #include at the top of main.c and program.c. For example, main.c uses fgets and program.c uses puts. So both should #include <stdio.h>.
I'll leave the rest for you as an exercise.
Related
I have currently made this much of the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#define STRSIZE 21
struct PInven{
int count;
struct PItem{
char name[STRSIZE];
int amount;
}Pitem;
}Pinven;//this needs to be an output file
int ReadInProduce (){
//read in file and check to see if the file exist or not.
FILE * PinFile = fopen("produce.txt","r");
if (PinFile == NULL){
printf("ERROR: WRONG FILE");
}
else{
printf("I did it!!\n");
}
//assigning the value gotten into the struct variable(but need to maybe change this since it needs to be an output)
fscanf(PinFile,"%d",&Pinven.count);
printf("%d\n", Pinven.count);
int i;
for(i =0; i <Pinven.count; i++){
fscanf(PinFile,"%20s %d",Pinven.Pitem.name, &Pinven.Pitem.amount);
printf("%s %d\n",Pinven.Pitem.name, Pinven.Pitem.amount);
}
//making an array to hold the variables
//FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
return 0;
}
From there I want to get the file that is read to the structs to be printed out into an array so that later on I can make a function that will be able to compare to the to it.
Basically a store management system. Where the file of the inventory is read in and compared to the file that is store and return a new value for the amount of produce now either left or gained.
10 //number of items that will be stored in the store
apple 19
banana 31
broccoli 9
...
In general, it's a really bad idea to include header information in the file about the number of entries in the file. You want to be able to do stream processing, and that will be more difficult if you need that meta-data. More importantly, it is important to understand how to write the code so that you don't need it. It's not really that difficult, but for some reason people avoid it. One simple approach is just to grow the array for each entry. This is horribly inefficient, but for the sake of simplicity, here's an example that expects the file not not include that first line:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <limits.h>
#define STRSIZE 128
struct PItem{
char name[STRSIZE];
int amount;
};
struct PInven{
int count;
struct PItem *PItem;
};
static void
grow(struct PInven *p)
{
p->PItem = realloc(p->PItem, ++p->count * sizeof *p->PItem);
if( p->PItem == NULL ){
perror("out of memory");
exit(1);
}
}
int
ReadInProduce(struct PInven *P, const char *path)
{
FILE * PinFile = fopen(path, "r");
if( PinFile == NULL ){
perror(path);
exit(1);
}
char fmt[64];
int max_len;
max_len = snprintf(fmt, 0, "%d", INT_MAX);
snprintf(fmt, sizeof fmt, "%%%ds %%%dd", STRSIZE - 1, max_len - 1);
grow(P);
struct PItem *i = P->PItem;
while( fscanf(PinFile, fmt, i->name, &i->amount) == 2 ){
i += 1;
grow(P);
}
P->count -= 1;
fclose(PinFile); /* Should check for error here! */
return P->count;
}
int
main(int argc, char **argv)
{
struct PInven P = {0};
char *input = argc > 1 ? argv[1] : "produce.txt";
ReadInProduce(&P, input);
struct PItem *t = P.PItem;
for( int i = 0; i < P.count; i++, t++ ){
printf("%10d: %s\n", t->amount, t->name);
}
}
As an exercise for the reader, you should add some error handling. At the moment, this code simply stops reading the input file if there is bad input. Also, it would be a useful exercise to do fewer reallocations.
you should change Structure of PInven to it can save a dynamic array of Pitem with a Pitem pointer.
tested :
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define STRSIZE 21
typedef struct {
char name[STRSIZE];
int amount;
} Pitem;
struct PInven {
int count;
Pitem *pitem;
} Pinven; // this needs to be an output file
int main() {
// read in file and check to see if the file exist or not.
FILE *PinFile = fopen("produce.txt", "r");
if (PinFile == NULL) {
printf("ERROR: WRONG FILE");
} else {
printf("I did it!!\n");
}
// assigning the value gotten into the struct variable(but need to maybe
// change this since it needs to be an output)
fscanf(PinFile, "%d", &Pinven.count);
Pinven.pitem = (Pitem *)malloc(sizeof(Pitem) * Pinven.count);
printf("%d\n", Pinven.count);
int i;
for (i = 0; i < Pinven.count; i++) {
fscanf(PinFile, "%20s %d", Pinven.pitem[i].name,
&Pinven.pitem[i].amount);
// printf("%s %d\n",Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
for (i = 0; i < Pinven.count; i++) {
printf("%s %d\n", Pinven.pitem[i].name, Pinven.pitem[i].amount);
}
// making an array to hold the variables
// FILE * PoutFile = fopen("produce_update.txt","w");
fclose(PinFile);
// remember free
free(Pinven.pitem);
return 0;
}
I've encountered a problem trying to reduce the size of my code. What I was trying to do was passing either name or color to function writedata so that I wouldn't have to write it twice for each case.
typedef struct Pet{
char* name;
char* color;
} pet;
void writedata(pet *Pet, char string[], const char field[]){
gets(string);
Pet->field= (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
strcpy(Pet->field, string);
}
The call of the function:
writedata(Pet, string, name);
I'm quite sure I got something wrong.
update: the whole code http://ideone.com/Y7L8Hu
update2: I tried to implement it using offset according to BLUEPIXY's advice but it seems I misunderstand manipulations with fields using their addresses... I believe the problem could be that the fields aren't initialized in the first place, but then again, my aim is to initialize them.
typedef struct Pet{
char* name;
int legs;
char* color;
} pet;
void writedata(pet *Pet, size_t FIELD){
char string[50];
gets(string);
(char*)Pet+offsetof(struct Pet, FIELD) = (char*)malloc(strlen(string)+1);//I wanted it to be treated like Pet->name
strcpy((char*)Pet+FIELD, string);
}
That's not how C works. However, I think using string comparison can achieve what you need:
if (strcmp(field, "name") == 0)
{
Pet->name = ...
}
else if (strcmp(field, "color") == 0)
{
Pet->color = ...
}
And call it with a string literal:
writedata(Pet, string, "name");
Using enum is also an option.
BTW, don't use gets, it's dangerous, use fgets instead.
use macro function sample.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define writedata(var, buffer, field) \
do {\
int len = strlen(buffer);\
var->field = (char*)malloc(len + 1);\
memcpy(var->field, buffer, len+1);\
}while(0)
typedef struct Pet{
char* name;
int legs;
char* color;
char* voice;
} pet;
void addpet(pet* Pet, int *TotalLegs){//Can not be used reference(&) in C
char buff[50];
int len;
puts("Input name");
scanf("%49[^\n]", buff);
writedata(Pet, buff, name);
puts("How many legs?");
scanf("%d%*c", &Pet->legs);
puts("What does it say?");
scanf("%49[^\n]%*c", buff);
writedata(Pet, buff, voice);
puts("_____\n");
*TotalLegs += Pet->legs;
}
int main(){
int TotalLegs = 0;
pet* Pet1 = (pet*)malloc(sizeof(pet));
addpet(Pet1, &TotalLegs);
pet* Pet2 = (pet*)malloc(sizeof(pet));
addpet(Pet2, &TotalLegs);
pet* Pet3 = (pet*)malloc(sizeof(pet));
addpet(Pet3, &TotalLegs);
//printf("%s\n", Pet1->name);
//printf("%s\n", Pet1->voice);
printf("The animals have %d legs\n", TotalLegs);
free(Pet1);free(Pet2);free(Pet3);
return 0;
}
A lot of things are wonky in your code.
What you wish to do can be achieved but it takes different type of code than you'd want to write.
What you really want to do is simply create a function that fills in a name and a color.
So here is the simplest way to do it:
typedef struct pet {
char *name;
char *color;
} pet_t;
pet_t * new_pet(const char *name, const char *color)
{
pet_t *p;
p = malloc(sizeof(pet_t));
if ( p == NULL )
return NULL;
p->name = strdup(name); /* allocate space and copy string */
p->color = strdup(color); /* allocate spance and copy string */
return p;
}
void delete_pet(pet_t *p)
{
if ( p-> name )
free(p);
if ( p->color)
free(color);
if ( p )
free(p);
}
int main() {
pet_t *p;
p = new_pet("Harry", "brown");
printf("%s is a %s pet\n", p->name, p->color);
delete_pet(p);
return 0;
}
I've declared a struct like this.
typedef struct fileProperties //the struct.
{
char name[256]; /*File or directory name*/
int mode; /*protection and file type*/
int userId; /*User ID of owner*/
int groupId; /*Group ID of owner*/
int size; /*file size in bytes*/
char modifyTime[50]; /*modify time as a string*/
} FILES;
I would like to write to the properties of file1, in a function call like this.
int createStruct()
{
char structBuffer[251];
printf("\n > Please enter a file name to create a struct for.> ");
inputFix(structBuffer, STRUCT_SIZE);
strncpy(file1.name, structBuffer, sizeof(structBuffer));
printf(" > Created.");
return 0;
}
Where inputFix is:
void inputFix(char string[],int length)
{
int ch, len = 0;
fgets(string, length, stdin);
string[strcspn(string, "\r\n")] = '\0';
len = strlen(string);
if (len == length - 1)
{
while((ch = getchar()) != '\n' && ch != EOF);
}
}
STRUCT_SIZE is defined as a size of 250.
At the top of my code I have this statement.
FILES file1;
I have read a couple of tutorials from coding unit and tutorials point in relation to structs.
I can't see why i get an error:
functions.c:59:3: error: unknown type name ‘FILES’
functions.c:62:52: error: request for member ‘name’ in something not a structure or union
Is it not worth using typedef? Am I missing something in relation to using structs, if so a link to another similar question would be appreciated.
It might be relevant that this program is split into 2 files main.c functions. c & .h. Do I need to include the struct in the linker file? the main.c only calls createStruct().
I suppose that the definition of variable FILE file1 is in main.c while function createStruct in file functions.c. In such case, you need to put:
extern FILES file1;
into your hedaer file and to include it at the beginning of functions.c. Otherwise the compiler does not know that there is the variable file1 defined in another file.
So your header.h will look like this:
typedef struct fileProperties //the struct.
{
char name[256]; /*File or directory name*/
int mode; /*protection and file type*/
int userId; /*User ID of owner*/
int groupId; /*Group ID of owner*/
int size; /*file size in bytes*/
char modifyTime[50]; /*modify time as a string*/
} FILES;
extern FILES file1;
Your main.c will look like:
#include "header.h"
FILES file1;
...
and your functions.c will look like
#include "header.h"
int createStruct()
{
...
strncpy(file1.name, structBuffer, sizeof(structBuffer));
...
I want to ask about file processing and struct in C language, I get an assignment from my lecture, and am so really confused about string manipulation in C programming. Here is the task.
get data from mhs.txt
store in struct
sort by name ascending
Here is the mhs.txt
1701289436#ANDI#1982
1701317124#WILSON#1972
1701331734#CHRISTOPHER STANLEY#1963
1701331652#SHINVANNI THEODORE#1962
1701331141#MUHAMMAD IMDAAD ZAKARIA#1953
1701331564#MARCELLO GENESIS DRIET J.#1942
1701322282#ANANDA AULIA#1972
1701329175#LORIS TUJIBA SOEJONOPOETRO#1983
1701301422#DEWI JULITA#1993
1701332610#HARRY HUTALIANG#1982
first before # is NIM,
after first # is name
and the last after #, is year
and here is what i've done
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student{
char nim[11];
char name[50];
int year;
}s[10];
int main(){
FILE *fp;
int c,i,n;
printf("Read mhs.txt...");
getchar();
fp = fopen("mhs.txt", "r");
c = getc(fp);
i = 0;
while(c!=EOF){
printf("%c", c);
c = getc(fp);
i++;
}
fclose(fp);
getchar();
return 0;
}
First thing, I could save data on struct, but in here I very confused to separate a string.
That's all I know about struct and file processing, is there anyone who can help me? I have traveled around the internet and could not find the correct results.
Sorry if there are duplicate questions, and sorry if my english is too bad.
This is pure C code, you should new three import function: strtok & qsort & fsan.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student
{
char nim[11];
char name[50];
int year;
};
#define BUFFER_SIZE 100
struct student saveToStruct (char* str)
{
struct student res;
int flag = 0;
char *token = strtok(str, "#");
while( token != NULL )
{
if (0 == flag)
strcpy(res.nim, token);
else if (1 == flag)
strcpy(res.name, token);
else
res.year = atoi(token);
flag++;
token = strtok( NULL, "#" );
}
return res;
}
void print(struct student* arr, int size)
{
for (int i = 0; i < size; i++)
{
printf("%s, %s, %d\n", arr[i].nim, arr[i].name, arr[i].year);
}
}
int cmp(const void* l, const void* r)
{
return strcmp(((const student*)l)->name, ((const student*)r)->name);
}
int main()
{
struct student arr[10];
FILE* file = fopen("mhs.txt", "r");
if (!file)
return -1;
char buffer[BUFFER_SIZE];
int flag = 0;
while (fgets(buffer, BUFFER_SIZE, file))
{
arr[flag] = saveToStruct(buffer);
flag++;
}
print(arr, 10);
qsort(arr, 10, sizeof(struct student), cmp);
printf("After sort by name!\n");
print(arr, 10);
return 0;
}
Since you've tagged this as C++, I'd use C++:
#include <iostream>
#include <string>
#include <algorithm>
struct student {
std::string nim;
std::string name;
int year;
bool operator<(student const &other) {
return name < other.name;
}
friend std::istream &operator>>(std::istream &is, student &s) {
std::getline(is, s.nim, '#');
std::getline(is, s.name, '#');
return is >> s.year;
}
};
int main() {
std::ifstream in("mhs.txt");
std::vector<student> students{
std::istream_iterator<student>(in),
std::istream_iterator<student>()
};
std::sort(students.begin(), students.end());
}
If you want to accomplish roughly the same thing in C, it's probably easiest to do the reading with fscanf using a scanset conversion, like:
fscanf(infile, "%10[^#]#%49[^#]#%d", student.nim, student.name, &student.year);
The scanset conversion gives you something like a subset of regular expressions, so the %[^#] converts a string of characters up to (but not including) a #. In this case, I've limited the length of each to one less than the length you gave for the arrays in your struct definition to prevent buffer overruns.
Then you can do the sorting with qsort. You'll need to write a comparison function, and doing that correctly isn't always obvious though:
int cmp(void const *aa, void const *bb) {
student const *a = aa;
student const *b = bb;
return strcmp(a->name, b->name);
}
Here are some hints, not the full answer. Hope it could help you.
first you need to read the file line by line, instead of character by character. You need the function of fgets(). you may find the reference from www.cplusplus.com/reference/cstdio/fgets/
second you can use strtok() to seperate strings. here is an example.
char str[] = "now # is the time for all # good men to come to the # aid of their country";
char delims[] = "#";
char *result = NULL;
result = strtok( str, delims );
while( result != NULL ) {
printf( "result is \"%s\"\n", result );
result = strtok( NULL, delims );
}
and you may find the reference to strtok() from http://www.cplusplus.com/reference/cstring/strtok/
third, use qsort() to sort the structure array. you may find the reference of it from http://www.cplusplus.com/reference/cstdlib/qsort/. examples can also be found there.
Im making an application that uses of API-threads in C, The program takes N-files (N>2) with names disordered,per each file is generated a thread of execution which sort the files using the function qsort, after being ordered files, each thread should create a file keeping the original file intact and displaying the sorted file to another file with the extension <.sorted>. The program sorts the numbers without problems, even if I put standard output displays the result on screen, but when I try to create the output file with extension .sorted the program breaks out.
this is my code file.c
#include <stdio.h> /* Standard buffered input/output */
#include <stdlib.h> /* Standard library functions */
#include <string.h> /* String operations */
#include <pthread.h> /* Thread related functions */
#include "pf1.h" /* Header specific to this app */
pthread_attr_t attr;
void *thread_worker(void *name_file)
{
FILE *entrada, *salida;
char* nombres = (char*)name_file;
int numero;
char temp [10000];
int i;
stats_t estadisticas;
printf ("File_name:%s\n", nombres);
entrada = fopen(nombres, "r");
salida = fopen (strcat(nombres, ".sorted"), "w");
while (!feof(entrada)){
fscanf (entrada, "%s\n",temp);
numero++;
}
char* lista[numero]; //array to sort the file
rewind (entrada);
for (i=0;i<numero;i++)
{
fscanf(entrada," %[^\n]", temp);
lista[i] = (char*)malloc((strlen(temp)+1)*sizeof(char));
strcpy(lista[i], temp);
}
size_t large = sizeof(lista) / sizeof(char *);
qsort(lista,large ,sizeof(char *) ,cstring_cmp );
printf ("Archivo Ordenado\n", i+1);
for (i=0;i<large;i++)
printf("%s\n",lista[i]);
pthread_exit(NULL);
}
int main(int argc, char *argv [])
{
stats_t **stats;
int i, rc;
pthread_t my_threads[argc-1];
pthread_attr_init(&attr);
if (argc <3) {
printf ("|files| > 2\n");
}else{
printf("files to sorted: %d\n", argc - 1);
for (i = 1; i < argc; i++){
//printf("%s%s\n", argv[i], (i < argc-1) ? " " : "");
rc = pthread_create(&my_threads[i], &attr, thread_worker, (void *)argv[i]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n",rc);
return -1;
}
}
}
return 0;
} /*end main */
this is mi file.h
#ifndef PF1_H_
#define PF1_H_
typedef struct _stats_t
{
char *longest, *shortest;
unsigned int numlines;
} stats_t;
int cstring_cmp(const void *a, const void *b)
{
const char **ia = (const char **)a;
const char **ib = (const char **)b;
return -strcasecmp(*ia, *ib);
/* strcmp functions works exactly as expected from
comparison function */
}
void print_cstring_array(char **array, size_t len)
{
size_t i;
for(i=0; i<len; i++)
printf("%s | ", array[i]);
putchar('\n');
}
#endif /* PF1_1_H_ */
I would like some help with this problem because I can not see which is the fault ... thanks to all in advance and excuse my English
This line here may be your problem:
salida = fopen (strcat(nombres, ".sorted"), "w");
From what I can tell, that nombres variable is coming from argv. Since you're not the one allocating memory for argv, you don't know that there will be extra space for the ".sorted" (and there probably won't be). If you strcpy it to your own buffer with space for the ".sorted", you should be fine.
#define EXT_LEN 7
#define MAX_TOTAL_LEN 250
#define MAX_FILE_LEN 242 //MAX_TOTAL_LEN - EXT_LEN - 1
char *name_ptr;
char nombres[MAX_TOTAL_LEN];
int len;
name_ptr = (char*)name_file;
len = strlen(name_ptr);
if (len > MAX_FILE_LEN) {
len = MAX_FILE_LEN;
}
strncpy(nombres, name_ptr, len);
strcpy(nombres+len, ".sorted");
salida = fopen (nombres, "w");
I once had issues about not passing an int identifier while calling thread execution functions. Try building a struct with both an integer identifier and the filename, then pass it as a parameter to your thread_worker() function.