I have just started using structs and I am trying to append the variable names and its contents to the struct variables. For example.
INPUT:
PATH, getenv("PATH")
OUTPUT:
Var Name: PATH
Var Contents: /usr/sbin
This is my struct declaration
int var_counter = 0;
typedef struct ENV_VARIABLES
{
char var_name[MAX_VAR_NAME]; // Stored the Variable Name ie PATH
char var_content[MAX_SIZE]; // Stores the Variable Contents ie \home\bin\shell...
}env_variable;
env_variable *env_vars;
Here I am passing the parameters to the environVars() then printing them.
void iniEnvVars()
{
environVars("PATH", getenv("PATH"));
environVars("PROMPT", shellname);
environVars("CWD", getcwd("CWD", MAX_ARGS));
environVars("USER", getenv("USER"));
environVars("SHELL", "/home/.../");
environVars("TERMINAL", ttyname(STDIN_FILENO));
environVars("EXITCODE", EXITCODE);
printVars();
}
Here I am adding the contents to the struct.
int environVars(char *env_name, char *env_content)
{
// First we want to check if there are any stored items in the struct
// If there isnt, we store the first env_name and its contents;
// Else, we check if it is there, else we add it to the struct.
// If it is already there we modify its contents.
if(var_counter == 0)
{
var_counter++;
env_vars = calloc((size_t)var_counter, sizeof(env_variable));
strcpy(env_vars[var_counter].var_name, env_name);
strcpy(env_vars[var_counter].var_content, env_content);
}
else
{
for(int i = 0; i < var_counter; i++)
{
if(strcmp(env_name, env_vars[i].var_name) == 0)
{
printf("Found\n");
printf("Modifying Variable Contents\n");
strcpy(env_vars[i].var_content, env_content);
break;
}
else
{
var_counter++;
env_vars = realloc(env_vars,(var_counter)*sizeof(env_variable));
strcpy(env_vars[i].var_name, env_name);
strcpy(env_vars[i].var_content, env_content);
break;
}
}
}
return 1;
}
Here I am printing them.
void printVars()
{
if(var_counter == 0)
{
printf("There are no Enviromental Variables stored.\n");
}
else
{
for(int i = 0; i < var_counter; i++)
{
printf("Var Name: %s\n\n ", env_vars[i].var_name);
printf("Var Contents: %s\n\n ", env_vars[i].var_content);
}
}
}
I made use of calloc and realloc, but I am not quite sure if I were supposed to use malloc.
The error occuring is that it is not printing anything.
Ive did run a debug and the same thing happened. Nothing was printing.
Bug #1:
if(var_counter == 0)
{
var_counter++;
env_vars = calloc((size_t)var_counter, sizeof(env_variable));
strcpy(env_vars[var_counter].var_name, env_name);
strcpy(env_vars[var_counter].var_content, env_content);
}
What actually happen when var_counter is zero, is this:
var_counter = 1;
env_vars = calloc(1, sizeof(env_variable));
strcpy(env_vars[1].var_name, env_name);
strcpy(env_vars[1].var_content, env_content);
^
oh dear
You are writing outside the allocated memory
It should be:
strcpy(env_vars[0].var_name, env_name);
strcpy(env_vars[0].var_content, env_content);
Bug #2:
for(int i = 0; i < var_counter; i++)
{
if(strcmp(env_name, env_vars[i].var_name) == 0)
{
printf("Found\n");
printf("Modifying Variable Contents\n");
strcpy(env_vars[i].var_content, env_content);
break;
}
else
{
// YOU DON'T WANT THIS !!
var_counter++;
env_vars = realloc(env_vars,(var_counter)*sizeof(env_variable));
strcpy(env_vars[i].var_name, env_name);
strcpy(env_vars[i].var_content, env_content);
break;
}
}
The else makes reallocate and overwrite old entries again and again. You don't want that.
The code in the else should be after the loop. And only be executed in no match was found in the loop.
Related
I am trying to divide my code into functions, I have a sample code of "Game Of Life".
However, when I try to initialize 2D grid array in a function, gnuplot gives no valid data points error.
These are global variables declared before main:
static char **currWorld=NULL, **nextWorld=NULL
This is the original logic to init game grid, but this part is in main.
if (game == 0){ // Use Random input
for(i=1;i<nx-1;i++){
for(j=1;j<ny-1;j++) {
currWorld[i][j] = (real_rand() < prob);
population[w_plot] += currWorld[i][j];
}
}
}
else if (game == 1){ // Block, still life
printf("2x2 Block, still life\n");
int nx2 = nx/2;
int ny2 = ny/2;
currWorld[nx2+1][ny2+1] = currWorld[nx2][ny2+1] = currWorld[nx2+1][ny2] = currWorld[nx2][ny2] = 1;
population[w_plot] = 4;
}
else if (game == 2){ // Glider (spaceship)
printf("Glider (spaceship)\n");
// Your code codes here
}
else {
printf("Unknown game %d\n",game);
exit(-1);
}
This is my function:
int init_game(int choice, int probability){
int i,j;
if (choice == 0){ // Use Random input
for(i=1;i<nx-1;i++){
for(j=1;j<ny-1;j++) {
currWorld[i][j] = (real_rand() < probability);
population[w_plot] += currWorld[i][j];
}
}
}
else if (choice == 1){ // Block, still life
printf("2x2 Block, still life\n");
int nx2 = nx/2;
int ny2 = ny/2;
currWorld[nx2+1][ny2+1] = currWorld[nx2][ny2+1] = currWorld[nx2+1][ny2] = currWorld[nx2][ny2] = 1;
population[w_plot] = 4;
}
else if (choice == 2){ // Glider (spaceship)
printf("Glider (spaceship)\n");
// Your code codes here
}
else {
printf("Unknown game %d\n",choice);
exit(-1);
}
}
and my function call in main:
init_game(game, prob);
value of game is 0, prob is 0.2 and I tested memory allocations and other stuff, they work fine.
Only difference is I moved the logic to a function. How can this happen? My arrays are global, I cannot understand how it cannot be initialized.
This is the gnuplot error:
Skipping data file with no valid points
Since gnuplot and other functions are works fine, I did not add them but if you need any info, I can add.
Here is the link of file itself:
file
I know homework help are shunned upon, however, I have intense coder's block.
I want help understanding more than anything.
So when I take the address of the variable (&c) I understand that I get an address to its location in memory, but I don't know how to dereference that address in order to access its specific value ('b') to be compared in the function (color(&c, total) it is used in.
The main cannot be changed for any reason due to the requirements of the assignment
typedef struct dragon
{
char *name;
char *color[3];
int numHead;
int numTail;
}dragon;
void color(char* color, dragon *d);
int main()
{
dragon total[4];
dragon_info(total);
char c = 'b';
color(&c, total);
return 0;
}
Eventually, I used this line to see if the colors matched
if(strcmp(color, d[currentDra].color[currentColor]);
Before I used the line below because from my from my first perspective they would char
if(color == d[currentDra].color[currentColor])
But after debugging for a while I realized that color was just an address
Overall, I need to somehow get the value of color using the address somehow.
*color doesn't find the value.
&color doesn't either.
The rest of the function
void color(char *color, dragon *d)
{
char *colorList[5] = {"red","blue","white","green","yellow"};
int colorShow;
int knownColor = 1;
printf("what is color? ==== %p\n", color);
if(*color == 'r')
{
colorShow = 0;
}
else if(*color == 'b')
{
colorShow = 1;
}
else if(*color == 'w')
{
colorShow = 2;
}
else if(*color == 'g')
{
colorShow = 3;
}
else if(*color == 'y')
{
colorShow = 4;
}
else
{
printf("Sorry that is an unknown color, exiting...\n");
knownColor = 0;
}
//if a char then = numbers 0-1
//one loop for the dragons
if(knownColor)
{
printf("***All the %s dragons:***\n", colorList[colorShow]);
int currentDra;
for(currentDra = 0; currentDra < 4; currentDra++)
{
//another loop for the colors of the dragon
int currentColor;
for(currentColor = 0; currentColor < 3; currentColor++)
{
//printf("%c\n\n", (char*)color);
if(strcmp(color, d[currentDra].color[currentColor]))
{
printf("%s is %s\n", d[currentDra].name, colorList[colorShow]);
}
}
}
}
}
Thank you so much this is my first question ever.
if(strcmp(color, d[currentDra].color[currentColor]);
This doesn't work because color, as passed, is not null terminated. Thus this is undefined behavior.
if(color == d[currentDra].color[currentColor])
This doesn't work because you are comparing the pointers and not the values they reference.
If dragon.color is an array that contains single character strings, then you can compare with:
if(color[0] == d[currentDra].color[currentColor][0])
I am trying to make a program that has a menu and it has an option to set the "current" date. I can define the date and it will stay until the program shuts down. I've got another method to get the date, by asking the user the date when linking a person to it, the problem is that it wont go on the main data on the main menu. It will only be the data for the .date on the person structure, I guess I explained it well. I've tried many ways and I really can't figure it out, if someone can help me out...
typeData readData() {
int val;
typeData data;
do {
printf("Day: ");
data.day = readInteger(MIN_DAYS, MAX_DAYS);
printf("Month: ");
data.month = readInteger(MIN_MONTH, MAX_MONTH);
printf("Year: ");
data.year = readInteger(MIN_YEAR, MAX_YEAR);
val = validateData(data);
if(val == 0) {
printf("The data is not valid.\n");
}
} while (val == 0);
return data;
}
I think I need to get it by reference but I'm trying for some time already and can't do it. Thanks everyone.
While it's legal C, passing structs by value and returning them is usually not the best way. Consider:
void
readData(typeData *data)
{
int val;
do {
printf("Day: ");
data->day = readInteger(MIN_DAYS, MAX_DAYS);
printf("Month: ");
data->month = readInteger(MIN_MONTH, MAX_MONTH);
printf("Year: ");
data->year = readInteger(MIN_YEAR, MAX_YEAR);
val = validateData(data);
if (val == 0) {
printf("The data is not valid.\n");
}
} while (val == 0);
}
UPDATE:
Here is a sample main program plus sample changes to validateData:
int
validateData(typeData *data)
{
int data_valid = 1;
// check for error
// this is whatever checks you already do ...
if (data->... != ...)
data_valid = 0;
return data_valid;
}
int
main(int argc,char **argv)
{
typeData main_data;
readData(&main_data);
// do something useful with the data [or transform it, etc]
processData(&main_data);
// print some results
printData(&main_data);
return 0;
}
UPDATE #2:
Here's a modified [partial] program, based on your latest example. I had to guess at the overall organization, but, at least it has the necessary changes to menuPrincipal:
int
validateData(typeData *data)
{
int data_valid = 1;
// check for error
// this is whatever checks you already do ...
if (data->... != ...)
data_valid = 0;
return data_valid;
}
char
menuPrincipal(typeDate *date)
{
char option;
if (date->day == 0 && date->month == 0 && data->year == 0) {
printf("Date not set yet.\n");
}
else {
printf("Date: %d/%d/%d", date->day, date->month, date->year);
}
// more stuff
return option;
}
int
main(int argc,char **argv)
{
typeData main_data;
char option;
while (1) {
readData(&main_data);
option = menuPrincipal(&main_data);
switch (option) {
case 'a': // do something
break;
case 'b': // do something else
break;
default:
printf("unknown option: '%c'\n",option);
break;
}
}
return 0;
}
UPDATE #3:
Based on your latest comment, I think I see what you're having trouble with. I've taken your latest code snippet and updated:
// your original code -- this no longer works because readData is now void
if (data->ano == 0 && data->mes == 0 && data->dia == 0) {
Blah[*Bleh].date = readData(*data);
}
// one possibility -- but it does _not_ update "data"
if (data->ano == 0 && data->mes == 0 && data->dia == 0) {
readData(&Blah[*Bleh].date);
}
// this is more likely what you want -- it updates _both_:
if (data->ano == 0 && data->mes == 0 && data->dia == 0) {
readData(data);
Blah[*Bleh].date = *data;
}
It works now, I was using
val = validateDate(&date)
on the original function for readData, now I changed it to
val = validateDate(date)
and it works!
I just don't know why I need to use date instead of &date, I thought that if I was passing the parameters by reference I needed a '&' symbol.
I have some functions that should allow me to manage a structure which was allocated dynamically. The allocation of the memory and the input of data in those is no real problem, though my program stops when it reaches a certain line of code: (No warning or problems detected)
if(codeV == p_vendite[ctrl_j].p_venditore[ctrl_i].codVenditore)
This line is in the function called VenditeProdotto(Vendite *p_vendite).
Here's the important part of the code (defining structures)
typedef struct _Venditore {
int codVenditore;
int codProdotto;
int qty;
} Venditore;
typedef struct _Vendite{
int mmGG;
Venditore *p_venditore;
} Vendite;
void AggiungiVendita (Vendite *p_vendite);
void VenditeProdotto(Vendite *p_vendite);
void VenditeVenditore(Vendite *p_vendite);
...
Here's main():
int main() {
int check, i, count, flag, choice;
Vendite *p_Vendite;
...
...
p_Vendite = (Vendite*) calloc(numVenditori,sizeof(Vendite));
...
...
p_Vendite->p_venditore = (Venditore*)calloc(numVenditori,sizeof(Venditore));
/*menu*/
flag = TRUE;
do{
choice = menu();
switch (choice) {
case 1 : AggiungiVendita(p_Vendite); break;
...
case 3 : VenditeProdotto(p_Vendite); break;
case 4 : VenditeVenditore(p_Vendite); break;
...
}
} while (flag == TRUE);
return 0;
}
And here are the functions:
void AggiungiVendita (Vendite *p_vendite) {
int flag, check, answer;
i = 0;
do{
/*input of struct - codVenditore,codProdotto,qty*/
...
check = scanf("%d", &(p_vendite[j].p_venditore[i].codVenditore));
...
/*input*/
check = scanf("%d", &(p_vendite[j].p_venditore[i].codProdotto) );
...
/*controllo sull'input*/
check = scanf("%d", &(p_vendite[j].p_venditore[i].qty) );
...
...
//asking to redo or quit
} while(flag == TRUE && i < numVenditori);
return;
}
int menu() {
//just a standard menu, no problem here
...
return choice;
}
void VenditeProdotto(Vendite *p_vendite) {
int check = 0, codeP = 0, ctrl_i = 0, ctrl_j = 0; //ctrl_i,ctrl_j are increasing variables and I use them to search among the structures
...//input, continues after
Where I find the debug error: (line 3 after this)
for(ctrl_j = 0; ctrl_j < numVendite; ctrl_j++) {
for(ctrl_i = 0; ctrl_i < numVenditori; ctrl_i++) {
if (codeP == p_vendite[ctrl_j].p_venditore[ctrl_i].codProdotto)
printf("\nSeller %d, quantity sold: %d in day %d", p_vendite[ctrl_j].p_venditore[ctrl_i].codVenditore, p_vendite[ctrl_j].p_venditore[ctrl_i].qty, ctrl_j+1);
else
continue;
}
}
return;
}
Basically I don't know if it's really legit to use the first line of code that I've talked about, with . instead of ->, but if I try to change the syntax I get detected errors. Any ideas?
At first I thought about something like (p_vendite+ctrl_j)->(p_venditore+ctrl_i)->codProdotto, since it's a pointer but it doesn't seem working.
There are a couple of obvious bugs:
Allocation of Vendite
You're allocating numVenditori elements for p_Vendite, but later on you are iterating numVendite times over the same pointer:
p_Vendite = (Vendite*) calloc(numVenditori,sizeof(Vendite));
...
for(ctrl_j = 0; ctrl_j < numVendite; ctrl_j++) {
for(ctrl_i = 0; ctrl_i < numVenditori; ctrl_i++) {
if (codeP == p_vendite[ctrl_j].p_venditore[ctrl_i].codProdotto)
The allocation should read:
p_Vendite = (Vendite*) calloc(numVendite,sizeof(Vendite));
or as I would prefer it:
p_Vendite = calloc (numVendite, sizeof *p_Vendite);
Allocation of Venditore
p_Vendite->p_venditore = (Venditore*)calloc(numVenditori,sizeof(Venditore));
You're only allocating the p_venditore element for one of your Vendite structs. You need to allocate all of them in a loop:
for (int j = 0; j < numVendite; j++) {
p_Vendite[j].p_venditore = (Venditore*)calloc(numVenditori,sizeof(Venditore));
// And check for allocation errors
}
I can't figure out why my program is outputting seemingly random Windows paths as shown below.
\maven, : ORS=4 (id: 4677968)
m32\cmd.exe, ò: Æ (id: 5525087)
, : (id: 4653392)
It does this when looping through an array of structures I have and displaying the values inside. Funny thing is though that it works perfectly. If I add 5 entries, it still displays all of them accurately. Yet it prints the random paths shown above before everything else.
I'm going to attach the whole program because I honestly don't know where to narrow the problem down to. I'm new to C and especially new to manually handling memory. So that may be where the problem lies. Thanks ahead of time.
The program:
#include<stdio.h>
#include<string.h>
// Define structures
typedef struct Contact
{
int id;
char fname[24];
char lname[24];
char number[16];
} Contact;
typedef struct Phonebook
{
Contact* contacts;
int contacts_length;
int id_tracking;
} Phonebook;
// Define prototypes
Phonebook addContact(Phonebook);
Phonebook removeContact(Phonebook); // removeContact() prompts the user for information about whom they want to remove.
void viewContacts(Phonebook);
void exportContacts(Phonebook);
Contact findEntry(int, Phonebook);
Phonebook removeEntry(int, Phonebook); // removeEntry() can be called to explicitly remove the entry with the passed in integer id.
int main()
{
// Define variables
int menuChoice = 0, status = 1;
Phonebook phonebook;
phonebook.contacts = (Contact*) malloc(sizeof(Contact));
// Check memory allocation
if(phonebook.contacts == NULL)
{
printf("\nFatal error: Out of memory... now exiting.");
return;
}
// Handle the user
do
{
// Begin collecting and assigning data
printf("\nContact Menu\n");
printf("\n(1.) Add contact");
printf("\n(2.) Remove contact");
printf("\n(3.) View contacts");
printf("\n(4.) Export contacts");
printf("\n(5.) Exit");
printf("\n\nPlease choose a menu option (enter the number): ");
scanf("%d", &menuChoice);
// Interpret menu choice
switch(menuChoice)
{
case 1:
// Begin adding contact
phonebook = addContact(phonebook);
status = 1;
break;
case 2:
phonebook = removeContact(phonebook);
status = 1;
break;
case 3:
viewContacts(phonebook);
status = 1;
break;
case 4:
exportContacts(phonebook);
status = 1;
break;
case 5:
// Free memory
free(phonebook.contacts);
// See ya!
printf("\nGoodbye!");
status = 0;
break;
default:
printf("I'm sorry, I didn't quite understand that. Please try again.");
status = 1;
break;
}
}
while(status != 0);
// Return 0 for exit
return 0;
}
Phonebook addContact(Phonebook phonebook)
{
// Clear screen first
system("cls");
// Define contact and set random id
Contact entry;
entry.id = phonebook.id_tracking;
phonebook.id_tracking++;
// Obtain information
printf("First name (24 characters max): ");
scanf("%s", &entry.fname);
printf("Last name (24 characters max): ");
scanf("%s", &entry.lname);
printf("Telephone number (recommended format: ###-###-####): ");
scanf("%s", &entry.number);
// Handle memory allocation
if(phonebook.contacts_length > 1)
{
phonebook.contacts = (Contact*) realloc(phonebook.contacts, sizeof(Contact) * (phonebook.contacts_length + 1));
}
// Save the contact to the array and count up
phonebook.contacts[phonebook.contacts_length] = entry;
phonebook.contacts_length++;
printf("Contact saved!\n");
return phonebook;
}
Phonebook removeContact(Phonebook phonebook)
{
// First check to make sure they have saved contacts
if(phonebook.contacts_length < 1)
{
// No contacts saved, tell them
printf("\nYou haven't saved any contacts.\n");
return;
}
// Define variables
int i, chosenId = 0;
// Display contacts with their ids
for(i = 0; i < phonebook.contacts_length; i++)
{
Contact entry = phonebook.contacts[i];
printf("\n%s, %s (id: %d)", entry.lname, entry.fname, entry.id);
}
// Handle removal
printf("\n\nPlease enter the ID of the contact you would like to remove: ");
scanf("%d", &chosenId);
// Remove
Phonebook updatedPhonebook = removeEntry(chosenId, phonebook);
printf("Contact removed!\n");
return updatedPhonebook;
}
void viewContacts(Phonebook phonebook)
{
// First check to make sure they have saved contacts
if(phonebook.contacts_length < 1)
{
// No contacts saved, tell them
printf("\nYou haven't saved any contacts.\n");
return;
}
// Define variables
int i;
// Display contacts with their ids
for(i = 0; i < phonebook.contacts_length; i++)
{
Contact entry = phonebook.contacts[i];
printf("\n%s, %s: %s (id: %d)", entry.lname, entry.fname, entry.number, entry.id);
}
printf("\n");
return;
}
/*
* Experimenting with I/O in C
*/
void exportContacts(Phonebook phonebook)
{
// First check to make sure they have saved contacts
if(phonebook.contacts_length < 1)
{
// No contacts saved, tell them
printf("\nYou have no contacts to be exported.\n");
return;
}
// Define and initialize variables
int i;
char outputName[] = "contacts.txt";
FILE *contactFile = fopen(outputName, "w");
// Print message
printf("\nExporting contacts to .txt file... ");
// Print to the file
for(i = 0; i < phonebook.contacts_length; i++)
{
Contact entry = phonebook.contacts[i];
fprintf(contactFile, "%s, %s (id: %d): %s\n", entry.lname, entry.fname, entry.id, entry.number);
}
// Close the file
fclose(contactFile);
// Done
printf("Done!");
printf("\nData exported to contacts.txt located where this program was launched.");
}
Contact findEntry(int id, Phonebook phonebook)
{
int i;
for(i = 0; i < phonebook.contacts_length; i++)
{
Contact entry = phonebook.contacts[i];
if(entry.id == id)
{
return entry;
}
}
}
Phonebook removeEntry(int id, Phonebook phonebook)
{
// Define variables
int i, positionToFree;
// Search for the index of the entry to remove
for(i = 0; i < phonebook.contacts_length; i++)
{
Contact entry = phonebook.contacts[i];
if(entry.id == id)
{
positionToFree = i; // This is the position to be freed
}
// We've found what we need, break now
break;
}
// Loop starting at that entry and remove
for(i = positionToFree; i < phonebook.contacts_length; i++)
{
Contact temp = phonebook.contacts[i + 1];
phonebook.contacts[i] = temp;
}
// Count down for contacts_length
phonebook.contacts_length--;
// Return the updated contacts
return phonebook;
}
This sounds like undefined behaviour.
You never initialise phonebook.contacts_length. It could have any value. When you go to add an entry, it's quite possible that the realloc call fails. You don't check the return value, so you wouldn't know.
Bad juju.