Struct array won't print char variable from **args - c

I am creating a struct called Job and I want to create an array of struct Job. The name of my array is jobQueue I populate the array using commandline args. The instructor has it set up to where **args is being used. After the user inputs the name of the job and the execution time it gets added to the array. However, when I try to print jobQueue[0].name using the list() funct I have written, the name does not get printed. I'm trying to get my code set up to where I can print the name. I have provided a minimal version of my overall project that just focuses on the specific problem I am encountering and should compile and run fine.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/wait.h>
#include <stdint.h>
#define EINVAL 1
#define E2BIG 2
#define MAXMENUARGS 7
//structure job initialize
struct Job {
//initializing name variable
char *name;
int executionTime;
};
//init the array
struct Job jobQueue[5] = {0};
//cmd function provided by intructor
int cmd_run(int nargs, char **args) {
int execT;
sscanf(args[2], "%d", &execT);
run(args[1], execT);
return 0;
}
//cmd function provided by intructor
void cmd_list() {
list();
}
//cmd function provided by intructor
static struct {
const char *name;
int (*func)(int nargs, char **args);
} cmdtable[] = {
/* commands: single command must end with \n */
{ "r", cmd_run},
{ "run", cmd_run},
{ "list\n", cmd_list}
};
//cmd function provided by intructor
//this is the function that handles the arguments entered by the user
//provided it just in case someone needs to see how arguments are being
//processed
int cmd_dispatch(char *cmd) {
time_t beforesecs, aftersecs, secs;
u_int32_t beforensecs, afternsecs, nsecs;
char *args[MAXMENUARGS];
int nargs = 0;
char *word;
char *context;
int i, result;
void *Dispatcher(void *arg);
for (word = strtok_r(cmd, " ", &context);
word != NULL;
word = strtok_r(NULL, " ", &context)) {
if (nargs >= MAXMENUARGS) {
printf("Command line has too many words\n");
return E2BIG;
}
args[nargs++] = word;
}
if (nargs == 0) {
return 0;
}
for (i = 0; cmdtable[i].name; i++) {
if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) {
assert(cmdtable[i].func != NULL);
/* Call function through the cmd_table */
result = cmdtable[i].func(nargs, args);
return result;
}
}
printf("%s: Command not found\n", args[0]);
return EINVAL;
}
//adds job to the array using user arguments
void run(char name[], int executionTime) {
//creates a job using the arguments specified by user
struct Job job = {name, executionTime};
jobQueue[0] = job;
printf("\nJob added to queue now please type 'list'\n");
}
//name will not print here
void list() {
printf("\nSee how the name will not print below?\n");
char executionTimeStr[5];
for (int c = 0; c < sizeof (jobQueue) / sizeof (jobQueue[0]); c++) {
//prints job info formatted
if (jobQueue[c].name != NULL) {
sprintf(executionTimeStr, "%d", jobQueue[c].executionTime);
//job name will not print here, output is just left blank
printf("%s %20.8s", "Name", "ExecTime");
printf("%-10.15s %11.3s\n",
jobQueue[c].name,
executionTimeStr
);
}
}
}
int main(int argc, char *argv[]) {
printf("Welcome to our batch job scheduler\n");
printf("Please enter the following exactly: 'run job1 10' \n");
//ignore this, it handles my commandline parser
char *buffer;
size_t bufsize = 64;
buffer = (char*) malloc(bufsize * sizeof (char));
if (buffer == NULL) {
perror("Unable to malloc buffer");
exit(1);
}
while (1) {
printf("User Input: ");
getline(&buffer, &bufsize, stdin);
cmd_dispatch(buffer);
}
//ignore this, it handles my commandline parser
return 0;
}

Related

How do you assign structs into an array?

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;
}

Array of Structs strange output?

Can anyone give me some indication as to why array of structs doesn't print out properly ?
I think its something to do with the memory I have allocated to the struct I am unsure !!
Using mac osx mountain lion xcode 4 gcc
Thanks for any help completely stuck!!
(Please have patience I am only a student !)
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct{
char* one;
char* two;
} Node;
Node *nodes;
int count = 0;
//-----------------------------------------------------------------------
void add(char *one,char*two){
char x[40];
char y[40];
printf("reached..\n");
strcpy(x,one);
strcpy(y,two);
printf("--> X: %s\n",x);
printf("--> Y: %s\n",y);
Node newNode;
newNode.one = x;
newNode.two = y;
nodes[count]= newNode;
count++;
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void print(){
int x;
for (x = 0; x < 10; x++)
{
printf("%d : (%s, %s) \n",x,nodes[x].one, nodes[x].two);
}
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void check(char **arg)
{
if(strcmp(*arg, "Add") == 0)
{
add(arg[1],arg[2]);
}else if(strcmp(*arg,"print") == 0)
{
print();
}else{
printf("Error syntax Enter either: \n Add [item1][item2]\n OR \n print\n");
}
}
//-----------------------------------------------------------------------
void readandParseInput(char *line,char **arg)
{
if (fgets (line, 512, stdin)!= NULL) {
char * pch;
pch = strtok (line," \n\t");
int count = 0;
arg[0] = pch;
while (pch != NULL)
{
count++;
pch = strtok (NULL, " \n\t");
arg[count] =pch;
}
}else{
printf("\n");
exit(0);
}
}
//-----------------------------------------------------------------------
int main()
{
int size = 100;
nodes = calloc(size, sizeof(Node));
int i;
for(i = 0;i <100; i++){
printf("%s , %s \n",nodes[i].one,nodes[i].two );
// nodes[i].one = ".";
// nodes[i].two = ".";
}
char line[512]; /* the input line */
char *arg[50]; /* the command line argument */
while (1)
{
readandParseInput(line,arg);
if(arg[0] != NULL){
check(arg);
}
}
return(0);
}
You're keeping pointers to the following automatic variables:
char x[40];
char y[40];
These go out of scope when add() returns, leaving you with dangling pointers.
You either have to turn Node::one and Node::two into arrays, or allocate memory for them on the heap.
In you add() function, you cannot assign one struct to another via an = operator... you would have to copy it...
memcpy( &nodes[count], &newNode )
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *fn;
}NAME;
#define NAME_LEN 20
int main()
{
NAME name;
name.fn = (char *) calloc(NAME_LEN, sizeof(char));
strcpy(name.fn, "Namco");
printf("Name: %s\n", name.fn);
free(name.fn);
return 0;
}
you can't just assign a string like this in c
newNode.one = x;
newNode.two = y;
what is newNode.one referring to???
at Function add
newNode.one = x;
newNode.two = y;
to
newNode.one = strdup(x);
newNode.two = strdup(y);

qsort for structures c

Below is my code:
I cant seem to use qsort effectively... It turns my array into 0's after they are populated with names and start times... Is it a problem with my qsort call? or the qsort itself.
The header with the structures is as follows:
/**
* Simulation of a process scheduler
*/
//#ifndef SCHEDULER_H_
#define SCHEDULER_H_
#include <stddef.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
/* types */
/** units of time */
typedef long time;
/** process identifier */
typedef int pid;
/** Information about a job of interest to the task scheduler */
struct job_data {
/* pid of this process */
pid pid;
/* time process starts */
time start;
/* time needed to finish */
time finish;
/* time spent processing so far */
time scheduled;
/* Number of lines */
int lines;
};
struct job {
/* Various parameters used by the scheduler */
char job_id[20];
struct job_data parameters;
char *lines[20];
};
/* I/O Files */
//static char *inputFile;
char * in;
static FILE *input;
static FILE *cur;
/*Scheduled jobs indexed by PID*/
struct job list[20];
/* the next job to schedule */
//static struct job *job_next = NULL;
/* Time */
time clock;
/*Comparison for qsort*/
int compare_start(const void *x, const void *y)
{
const struct job *a = x;
const struct job *b = y;
printf("%ld, %ld\n", a->parameters.start, b->parameters.start);
if (a->parameters.start < b->parameters.start)
{
return -1;
}
if (a->parameters.start > b->parameters.start)
{
return 1;
}
return 0;
}
/*Order Jobs*/
static void order_jobs(void)
{
qsort(list, (sizeof list) / (sizeof list[0]), sizeof list[0], compare_start);
}
/** Read and parse input from input file */
static void parse_input(void)
{
char buffer[BUFSIZ];
char lines[BUFSIZ];
int jobs = 0;
struct job *current;
while( fgets(buffer, sizeof(buffer), input) )
{
time start;
char buf[BUFSIZ];
sscanf(buffer,"./%s/", buf);
cur = fopen(buf, "r" );
int n_lines = 0;
while( fgets(lines, sizeof(lines), cur) )
{
if( n_lines == 0 )
{
current = &list[jobs];
strcpy(current->job_id, buf);
sscanf(lines,"%ld", &start);
current->parameters.start = start;
}
n_lines++;
}
current->parameters.lines = n_lines;
jobs++;
fclose(cur);
}
order_jobs();
for (int i = 0; i < jobs; i++)
{
printf("%s %ld %d\n", list[i].job_id, list[i].parameters.start, list[i].parameters.lines);
}
}
int main(int argc, char **argv)
{
in = argv[1];
if ( (input = fopen(in, "r")) == NULL ) {
fprintf(stderr, "cannot open %s\n", argv[1]);
}
parse_input();
fclose(input);
return EXIT_SUCCESS;
}
You only load jobs entries into the array, but you tell qsort() to sort the entire array (20 elements). This probably puts non-initialized elements at the front, which you then print.

Wrong result when copying an array of strings

I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* user;
char* passwd;
int nr;
void test()
{
int i=0;
for(i=0;i<argc;i++)
printf("Hello %s \n",user);
}
int main(int argc,char*argv[])
{
int i;
nr=argc;
for (i=0; i<argc; i++)
{
user=strdup(argv[i]);
}
test();
return 0;
}
The result is the argv[argc] on all the positions. How can I fix this? I wwant to have that test() outside the loop.
**
EDIT
**
After the ANSWERS here this is my new code, which is not working. Can anyone say why?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* user;
void test(int n)
{
int i=0;
for(i=0;i<n;i++)
printf("%s \n",user[i]);
}
int main(int argc,char*argv[])
{
user = (char*) malloc(argc*sizeof(char));
int i;
for (i=0;i<argc;i++)
{
user[i]=argv[i];
}
test(argc);
return 0;
}
You are assigning to both password and user at each iteration of the for loop. The final values you see are from the last iteration. Also, there is memory leak due to overwriting the pointers from previous strdup calls. In fact, you do not need a loop:
int main(int argc,char*argv[])
{
if(argc == 3) {
user=strdup(argv[1]);
passwd=strdup(argv[2]);
} else {
// error: usage
}
test();
return 0;
}
If you want to have multiple user/password combinations:
char *user[256], *passwd[256];
void test(int n) {
int i;
for(i=0;i<n;i++)
printf("Hello %s \n",user[i]);
}
int main(int argc,char*argv[])
{
int i;
for(i = 0; i < argc && i < 256; i+=2) {
user[i]=strdup(argv[i]);
passwd[i]=strdup(argv[i+1]);
}
test(argc);
return 0;
}
Because you overwrite the pointers user and passwd in every iteration. Hence, you'll only see the last string.
If you can tell your aim of the program, a better answer can be provided. Because I am not sure whether you want to read one user and passwd Or an array of users and passwds.
After you edit, I see you want to read an array of strings:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** user;
// or char *user[100]; /* If you want a fix length array of pointers. Now, you dont have to malloc. /*
char* passwd;
int nr;
void test(int argc)
{
int i=0;
for(i=0;i<argc;i++)
printf("Hello %s \n",user[i]);
}
int main(int argc,char*argv[])
{
int i;
nr=argc;
user = malloc(argc*sizeof(char*));
for (i=0; i<argc; i++)
{
user[i]=strdup(argv[i]);
}
test(argc);
return 0;
}
Of course; in test() you don't use i other than a loop variable and in main() you keep overwriting the previous value of user and passwd. In effect, what you do is:
user = strdup(argv[0]); /* Note: argv[0] is the program name. */
passwd = strdup(argv[0]);
user = strdup(argv[1]);
passwd = strdup(argv[1]);
user = strdup(argv[2]);
passwd = strdup(argv[2]);
user = strdup(argv[3]);
passwd = strdup(argv[3]);
printf("%s %s \n", user, passwd);
With this information, can you fix your program?
$ cat trash.c
#include <stdio.h>
#include <string.h>
void test(FILE* stream, char* usr, char* pass) {
fprintf( stream, "%s#%s\n", usr, pass);
}
int main(int argc, char** argv) {
int i = 1;
if (argc % 2) {
while(argv[i]) {
test(stdout, argv[i], argv[i + 1]);
i += 2;
}
}
return 0;
}
$ clang trash.c
$ ./a.out user1 pass1 user2 pass2
user1#pass1
user2#pass2
$
also if you call strdup() don't forget to free memory, because strdup called malloc().

File handling using API thread in C

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.

Resources