This question already has answers here:
Can I initialize string after declaration?
(3 answers)
Closed 2 years ago.
In this code I tried to initialize and pass three strings to a function: action_type; system_type; room
(COLD, HOT, and EMP mean respectivly cooling system, hotting system and employee room).
The code code runs but it doesn't printf the strings. What can I do in order to visualize the strings?
Thanks all.
enter code here
#include <stdio.h>
#include <string.h>
#define T_MAX_EMP 25
#define T_MIN_EMP 15
#define ON 1
#define OFF 0
void SystemAction(char* action_type, char* system_type, char* room, bool power)
{
if(power == OFF)
{
printf ("%s %s %s \n", action_type, system_type, room);
power = ON;
}
else
{
if(power == ON)
{
printf("%s is still on \n", system_type);
}
}
}
void SystemCheck(int n, int system)
{
if(n == 1)
{
printf ("The heating / cooling system works correctly \n");
}
else
{
if(n == 0)
{
printf("System malfunctions have been reported \n");
system = n;
}
else
{
printf ("\n Value entered is incorrect \n");
}
}
}
int main()
{
int n;
int system = 1;
int ch;
int power = OFF;
char c;
char action_type[10];
char system_type[10];
char room[10];
do
{
printf("Enter the character and the integer: \n");
scanf (" %c %d" , &c, &n);
switch(c)
{
case 'e' :
if(system == 0)
{
printf("The system doesn't work \n");
}
else
{
if (n > T_MAX_EMP)
{
action_type[10] = "ON";
system_type[10] = "COLD";
room[10] = "EMP";
SystemAction(action_type, system_type, room, power);
}
else
{
if(n < T_MIN_EMP)
{
action_type[10] = "ON";
system_type[10] = "HOT";
room[10] = "EMP";
SystemAction(action_type, system_type, room, power);
}
}
break;
}
case 's' :
SystemCheck(n, system);
break;
}
printf("Continue? \n");
scanf(" %d", &ch);
}while(ch == 1);
return 0;
}
action_type[10] = "ON"; is not the proper way to assign strings.
You didn't get that code from any reference, book, training material.
Did you make up an entirely new syntax hoping it would work?
Look into strcpy
Arrays do not have the assignment operator.
In statements like these
action_type[10] = "ON";
system_type[10] = "COLD";
room[10] = "EMP";
it seems you want to assign arrays with string literals. However actually you are trying to assign non-existent elements of the arrays with pointers to first characters of the string literals.
What you need is to copy the string literals into arrays like
strcpy( action_type, "ON" );
strcpy( system_type, "COLD" );
strcpy( room, "EMP" );
If You are not going to change elements of the arrays then instead of arrays of characters you could use just pointers like
char *action_type;
char *system_type;
char *room;
In this case the statements like these
action_type = "ON";
system_type = "COLD";
room = "EMP";
will be correct.
Or even to declare the pointers with the qualifier const
const char *action_type;
const char *system_type;
const char *room;
In this case you will need also to change the function declaration
void SystemAction(char* action_type, char* system_type, char* room, bool power);
to the following declaration
void SystemAction( const char* action_type, const char* system_type, const char* room, bool power);
Firstly, your code have to #include <stdbool.h> for bool type.
Secondly, You should use strcpy for copying string to string in c.
strcpy(action_type,"ON");
strcpy(system_type,"COLD");
strcpy(room,"EMP");
and
strcpy(action_type,"ON");
strcpy(system_type,"HOT");
strcpy(room,"EMP");
When you use action_type[10] for example, this is 11th character of array action_type. "ON" is string not character. If you want to assign with character, use ' instead of ". For example
action_type[0] = 'O';
action_type[1] = 'N';
action_type[3] = '\0';
One more thing, action_type[10] is out of the array because the maximum index of action_type is 9 (from 0 to 9).
Related
I am currently building a symbol table program using C. It needs to stay as simple as possible while having the required functionality as I am expected to produce a working compiler by the end of the semester. I currently have a working implementation that creates entries into the symbol table from user input but it is not 100% where it needs to be. I just need some guidance based on the feedback I was given from my professor. I understand that there are some things I need to change, I am new to coding in C and I am also trying to learn Python and R at the same time so im a little overwhelmed. I know I need a separate initialize and print function, That there should be no Input or Output in the create function, and that every entry has a scope of 0. where I'm stuck at, is creating the functions for initialize and print without losing the current functionality that I already have. Any help is appreciated. Here is my current implementation of the code:
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct ADT {
char name[18]; // lexeme name
char usage;
char type; // I is integer, S is type string, I for identifier
int scope; // scope of where it was declared, inserted for later use
int reference;
};
typedef struct ADT new_type;
new_type table[200];
int i = 0;
int read(char *name, char usage, char type, char scope) { //Read function to read input and check for duplicates
for (int j = sizeof(table) / sizeof(table[0]); j >= 0; --j) {
if (strcmp(table[j].name, name) == 0 &&
table[j].usage == usage &&
table[j].type == type &&
table[j].scope == scope)
return 1; // found
}
return -1; // not found! that's good
}
int create( char *name, char usage, char type, char scope) { //Create function to insert new input into symbol table
strcpy(table[i].name, name);
table[i].usage = usage;
table[i].type = type;
table[i].scope = scope;
if (table[i].usage == 'I' && table[i].type == 'L')
table[i].reference = atoi(name);
else
table[i].reference = -1;
return i++;
}
int initialize(char *name, char usage, char type, char scope) { // Function to initialize the symbol table and clear it. also creates the fred lexeme
create("Fred", 'I', 'I', '0');
}
int print(char *name, char usage, char type, char scope) { // Print function to print the symbol table
printf("Nate's Symbol Table\n");
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
}
int main() { // Main function to take input and produce the symbol table lexemes
printf("Course: CSCI 490 Name: Nathaniel Bennett NN: 02 Assignment: A03\n");
printf("\n");
create("Fred", 'I', 'I', 0);
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
// keep asking for a lexeme until we type STOP or stop
while (1) {
char lexeme[256];
char nUsage;
char nType;
char nScope;
printf("Enter a lexeme: \n"); //enter lexeme name
scanf("%s", lexeme);
if (strcmp(lexeme, "stop") == 0) break;
printf("Enter its usage: \n");
scanf(" %c", &nUsage);
printf("Enter its type: \n");
scanf(" %c", &nType);
printf("Enter its scope: \n");
scanf(" %c", &nScope);
printf("%s, %c, %c, %c\n", lexeme, nUsage, nType, nScope);
create(lexeme, nUsage, nType, nScope);
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
}
printf("Nate's Symbol Table\n");
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
for (int j = 0; j < i; j++) {
if (table[j].name == NULL)
break;
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n", j, table[j].name, table[j].scope, table[j].type, table[j].usage, table[j].reference);
}
return 0;
}```
...I think we're normally reluctant to get up in people's course assignments, but you seem like you have thought about this for a while Nate.
I can't quite make out what your instructor is suggesting. I do not see I/O in your code for the create() function. Unless the call to strcpy() is considered I/O in their view.
I do see some room for improvement in your print() function though. Your function relies upon a global entity (table) and then it ties your loop both to an imaginary value (what is "i" in your loop initialization?) AND to a condition where your logic asks effectively, "did I run out of table?"
Choose one condition or the other. There is a semantic elegance in simply printing everything you find in the table. You can make the function better if you pass a reference to the table rather than code to the existence of a static global value. So instead of passing all those values to your print() function, how about just one argument? Pass a reference to table, and your function could then be used for other similar dump operations. It becomes more generalized, and that's a good thing.
I would also say this. I prefer using sprintf() to stage my output in a string and then when everything is ready, I output it all at one time. This is easier to inspect and debug.
Also, not related to your assignment I imagine, but be extra-vigilant every time you use scanf() -- it was often my number one suspect whenever I had a bad pointer.
Definitely try to isolate or eliminate calls to chaotic functions like that one.
Keep thinking about how to make your function stronger, keep refactoring. You'll do great!
There are a number of issues. This won't even compile:
read conflicts with the syscall (i.e. rename it)
read has UB (undefined behavior) because it starts the for loop at one beyond the end of the table array
The symbol printing code is replicated everywhere. Better to define a table printing function (e.g. tblprint) and a symbol printing function (e.g. symprint).
The format used to print a symbol uses (incorrectly) variable precision format specifiers (e.g.) %*s expects two arguments: int len,char *str With -Wall as a compile option, these statements are flagged.
AFAICT, ordinary format specifiers work fine.
The if (sym->name == NULL) will never be valid because it is a fixed length array. We need to use a char *.
Using i as a global for the count of the array is misleading. Try something more descriptive (e.g.) tabcount
Using table[i].whatever everywhere is cumbersome. Try using a pointer (e.g. sym->whatever)
initialize [and some others] need a return with a value.
I've used cpp conditionals to denote old code vs new code:
#if 0
// old code
#else
// new code
#endif
Here is the refactored code. It is annotated. It compiles cleanly and passes a rudimentary test:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
struct ADT {
// NOTE/BUG: the if (sym->name == NULL) will fail
#if 0
char name[18]; // lexeme name
#else
const char *name; // lexeme name
#endif
char usage;
// I is integer, S is type string, I for identifier
char type;
// scope of where it was declared, inserted for later use
int scope;
int reference;
};
#if 0
typedef struct ADT new_type;
new_type table[200];
#else
typedef struct ADT ADT;
ADT table[200];
#endif
int tabcount = 0;
// NOTE/BUG: "read" conflicts with a syscall name
#if 0
//Read function to read input and check for duplicates
int
read(char *name, char usage, char type, char scope)
#else
// find_entry -- find a matching entry (if it exists)
int
find_entry(char *name, char usage, char type, char scope)
#endif
{
// NOTE/BUG: this is UB (undefined behavior) because you're starting at one
// past the end of the array
#if 0
for (int j = sizeof(table) / sizeof(table[0]); j >= 0; --j) {
#else
for (int j = tabcount - 1; j >= 0; --j) {
#endif
ADT *sym = &table[j];
if (strcmp(sym->name, name) == 0 &&
sym->usage == usage &&
sym->type == type &&
sym->scope == scope)
return 1;
}
// not found! that's good
return -1;
}
//Create function to insert new input into symbol table
int
create(char *name, char usage, char type, char scope)
{
ADT *sym = &table[tabcount];
// NOTE/BUG: this needs to be a pointer to a string to allow long strings and
// for "if (sym->name == NULL)" to be valid
#if 0
strcpy(sym->name, name);
#else
sym->name = strdup(name);
#endif
sym->usage = usage;
sym->type = type;
sym->scope = scope;
if (sym->usage == 'I' && sym->type == 'L')
sym->reference = atoi(name);
else
sym->reference = -1;
return tabcount++;
}
// Function to initialize the symbol table and clear it. also creates the fred
// lexeme
int
initialize(char *name, char usage, char type, char scope)
{
create("Fred", 'I', 'I', '0');
return 0;
}
void
symprint(ADT *sym)
{
int j = sym - table;
// NOTE/BUG: with (e.g) %*d this is variable precision field -- it requires
// _two_ arguments: <int wid>,<int val>
#if 0
printf("%*d\t\t%*s\t%*d\t%*c\t%*c\t%*d\n",
j, sym->name, sym->scope, sym->type,
sym->usage, sym->reference);
#else
printf("%d\t\t%s\t%d\t%c\t%c\t%d\n",
j, sym->name, sym->scope, sym->type,
sym->usage, sym->reference);
#endif
}
void
tblprint(int title)
{
if (title)
printf("#\t\tName\tScope\tType\tUsage\tReference\n");
for (int j = 0; j < tabcount; j++) {
ADT *sym = &table[j];
if (sym->name == NULL)
break;
symprint(sym);
}
}
// Print function to print the symbol table
int
print(char *name, char usage, char type, char scope)
{
printf("Nate's Symbol Table\n");
tblprint(1);
return 0;
}
// Main function to take input and produce the symbol table lexemes
int
main()
{
printf("Course: CSCI 490 Name: Nathaniel Bennett NN: 02 Assignment: A03\n");
printf("\n");
create("Fred", 'I', 'I', 0);
tblprint(1);
// keep asking for a lexeme until we type STOP or stop
while (1) {
char lexeme[256];
char nUsage;
char nType;
char nScope;
// enter lexeme name
printf("Enter a lexeme: \n");
scanf("%s", lexeme);
if (strcmp(lexeme, "stop") == 0)
break;
printf("Enter its usage: \n");
scanf(" %c", &nUsage);
printf("Enter its type: \n");
scanf(" %c", &nType);
printf("Enter its scope: \n");
scanf(" %c", &nScope);
printf("%s, %c, %c, %c\n", lexeme, nUsage, nType, nScope);
create(lexeme, nUsage, nType, nScope);
tblprint(0);
}
printf("Nate's Symbol Table\n");
tblprint(1);
return 0;
}
It's my first time here on stackoverflow. I hope my question fits.
We started programming C at the university this semester. Unfortunately there are only a few online lectures. But we still have to solve the tasks.
We should program a kind of Hang-Man this time. In other words, guess a hidden word.
I have the following problem. I get a char, but after entering it, the contents of the riddle array change. If I leave out the input it works. I don't understand why this happens because scanf doesn't actually access riddle.
I myself don't know what to do here. I hope someone can tell me what's wrong with the code.
//sry some variables and texts are in german
char* createRiddle(char const* const str){
int laenge = strlen(str);
char temp[laenge+1];
char *t = temp;
strcpy(temp, str);
int te = strcmp(temp, str);
if (te != 0){
printf("ERROR: Bei der Speicherreservierung ist ein Fehler aufgetreten");
exit(0);
}
int i;
for (i=0; i < (int)strlen(temp);i++){
if (str[i] > 65 && str[i] < 90){ //ASCII Großbuchstaben-Bereich prüfen
char verdeckt = '*';
temp[i] = verdeckt;
} else {
temp[i] = str[i];
}
}
return t;
}
//----------------------------
int uncoverLetter(char *riddle, const char *solution, char letter){
printf("RD3: %s\n",riddle);
letter = toupper(letter);
int i;
int treffer = 0;
for (i=0; i < (int)strlen(solution); i++) {
if (letter == solution[i]) { // Buchstabe im Wort?
if (letter != riddle[i]) { //Buchstabe schon aufgedeckt?
riddle[i] = solution[i];
treffer = treffer + 1;
}
}
}
return treffer;
}
//----------
int gamingLoop(const char* solution){
int punkte; //points
printf("Lets GO!\n\n");
char *riddle = createRiddle(solution);
printf("Gesuchtes Wort: %s\n\n",riddle); //Word: *-******* ( = C-Compiler )
int highscore = 0;
while ((strcmp(riddle, solution)) != 0) {
printf("RD1: %s\n",riddle); //Test: What does Riddle look like?
printf("Bitte geben Sie einen Buchstaben ein: "); // pls enter letter
char eingabe;
scanf(" %c", &eingabe); //-----!!Here is the point where things go wrong!!------
printf("RD2: %s\n",riddle); //Test2
int treffer = uncoverLetter(riddle, solution, eingabe);
//----------- probably unimportant for the problem ----------------
//Zufallszahl
int zufz = (rand() % 11) + 1;
int ii = 1;
for (ii=1; ii < 11 ; ii++){
if ( zufz == ii) {
punkte = zufz*100;
}
}
//------------
if (treffer != 0) {
printf("Du hast %d richtige Treffer.\n", treffer);
highscore = highscore + (treffer*punkte);
printf("Punkte: %i\n\n", highscore);
} else {
printf("Du hast leider keinen Treffer.\n");
highscore = highscore - punkte;
printf("Punkte: %d\n\n", highscore);
}
printf("%s\n\n",riddle);
}
return highscore;
}
OUTPUT:
Sry no pic because i dont have 10 rep :(
Link: https://imgur.com/UIeltVR
// R3 in funktion uncoverLetter
I strongly suspect that I made a very stupid mistake, but unfortunately I can't see it myself / can't see it yet.
I look forward to advice and help.
Thank you.
Your problem is in createRiddle, where you create the *** pattern:
char* createRiddle(char const* const str){
int laenge = strlen(str);
char temp[laenge+1];
char *t = temp;
// ... create pattern ...
return t;
}
You return a local array. (t is just an alias to the array temp.) That array will be out of scope when the function exits and therefore invalid.
There are several possible solutions.
Make the caller provide space
Pass in an array that the caller can fill:
void createRiddle(char *temp, char const* const str)
{
// ... create pattern in temp ...
}
Then call it like this:
char riddle[MAX];
createPattern(riddle, solution);
You don't need to return the array here, because it is the same array you provided, only filled. (You could return it if it makes calling easier. You could also return an error code. Use your good judgement.)
Of course, the function and caller need to agree how much space must be provided. (That could be another function parameter or a global constant.)
Allocate memory dynamically
Dynamic memory is allocated on the heap and guaranteed not to be used by anyone else:
char *createRiddle(char const* const str)
{
int laenge = strlen(str);
char *temp = malloc(laenge + 1);
// ... create pattern in temp ...
return temp;
}
Then use it like this:
char *riddle = createRiddle(char const* const str);
// ... play the game ...
free(riddle); // be nice and clean up
Static arrays
Make the array static.
static char temp[laenge+1];
Here, the static keyword means that there is only one array that retains its value between calls. It is really as if you has declared the array as global outside the function, but with the addition that its name is only known to your function.
That's a quick and easy solution, but it fails when your function is recursive or when other parts of your code use the same function. (That's probably not the case in your game, though.)
I am trying to improve my C skills so I apologize if my question is long. I am having a hard time understanding as to why my struct pointer holds the wrong value in my program, I tried to debug it but I am still relatively new to C and was hoping one of you could tell me what I'm doing wrong here and how I could improve my code and what to focus on.
I am making a program that stores user data on this struct and then prints it out.
typedef struct table {
char *firstName;
char *lastName;
int id;
}USER;
This function below stores the first name
void firstName(int *counter, int *check, USER *pt) {
for (int i = *counter; i < *check; i++) {
pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt));
printf("Enter First Name: ");
getchar();
fgets(pt[i].firstName, MAX_LENGTH, stdin);
}
}
This is just my bool function returning true or false
bool isTrue(char *decision) {
if(*decision == 'Y') {
return true;
}
else {
return false;
}
}
And this is my main
int main(int argc, char **argv) {
USER *pt = calloc(1, sizeof(pt));
int counter = 0, check = 0;
char decision = '\0';
while (1) {
printf("Would you like to enter a user?(Y/N):");
fgets(&decision, 2, stdin);
strtok(&decision, "\n"); //remove the newline char
if (!isTrue(&decision)) {
break;
}
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //the 10 is temporary
}
check = counter + 1; // make sure loop only runs once.
firstName(&counter, &check, pt);
++counter; // increment counter;
}
printStruct(pt, &counter);
return 0;
}
When I run it out sometimes it works fine and returns everything and sometimes it skips a value. This is what I get. It skips the value at pointer index 1 and prints garbage instead.
Would you like to enter a user?(Y/N):N
First name at array 0 is Ermir
First name at array 1 is P#1First name at array 2 is Kevin
First name at array 3 is Blaus
First name at array 4 is Adam
Also I was wondering why is it when I realloc here If i do I get a realloc error when I enter the second name.
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //realloc(pt, sizeof(pt) * counter + 1) wont work
}
char decision = '\0';
...
fgets(&decision, 2, stdin);
You are only allocating 1 char but are at least reading 2 chars into it. Fix by allocating a sufficiently sized array for decision.
Unrelated but in firstName() pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt)); should be pt[i].firstName = calloc (MAX_LENGTH, 1);
Program specifications:
Read questions from a data file in the following format:
Question
Number of choices
N-amount of choices
Correct answer
Example:
What is the capital of France?
3
Madrid
Sydney
Paris
Paris
Present the user a question at a time and keep track of their score, etc, etc.
What I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE_SIZE 60
#define MAX_LIST_SIZE 15
#define MAX_QUIZ_SIZE 10
typedef struct question {
char *question;
char **choices;
int n_choices;
char *correct_answer;
} QUESTION;
typedef struct quiz {
struct question *questions;
int n_questions;
} QUIZ;
char *dupString(const char *s) {
// copies a string
char *dup = malloc(strlen(s) + 1);
strcpy(dup, s);
return dup;
}
void free_choices(QUESTION *q) {
// free memory
for(int i = 0; i < q->n_choices; i++) {
free(q->choices[i]);
}
free(q->choices);
}
int ask(QUESTION *q) {
// Return 1 for correct guess, 0 for incorrect guess.
int choice;
// Print the question
printf("\n%s\n", q->question);
// Print the choices
for (int i = 0; i <= q->n_choices-1; i++) {
printf("%d : %s", i+1, q->choices[i]);
}
// Get user guess
do {
printf("Select an answer [1-%d]: ", q->n_choices);
scanf("%d", &choice);
/* Not sure how to structure here*/
if (strcmp(q->choices[choice-1], q->correct_answer) == 0) {
// if correct return 1
return 1;
}
} while (choice < 1 || choice > q->n_choices);
// Incorrect
return 0;
}
struct question parseQuestion(FILE *pData) {
int qIndex, numChoices;
char question[MAX_LINE_SIZE], temp[MAX_LINE_SIZE], choices[MAX_LINE_SIZE], correctAns[MAX_LINE_SIZE];
QUESTION q = {NULL, NULL, 0, NULL};
// Eat first line = QUESTION
fgets(question, MAX_LINE_SIZE, pData);
q.question = question;
// Eat second line = NUMBER OF CHOICES
fgets(temp, MAX_LINE_SIZE, pData);
numChoices = atoi(temp);
q.n_choices = numChoices;
// Allocate memory
q.choices = calloc(q.n_choices, sizeof(char*));
// Eat nth lines = CHOICES
for (qIndex=0; qIndex<=numChoices-1; qIndex++) {
fgets(choices, MAX_LINE_SIZE, pData);
q.choices[qIndex] = dupString(choices);
}
// Eat nth + 1 line = CORRECT ANSWER
fgets(correctAns, MAX_LINE_SIZE, pData);
q.correct_answer = correctAns;
return q;
}
int main() {
int num = 0; // question being asked
int strikes = 0; // incorrect guesses
FILE* pData;
char *filename = "tickle.txt";
char c;
if ((pData = fopen(filename, "r"))) {
printf("Welcome to the 2014 Quiz-festival!\n\n");
printf("Are you ready to begin? [Y/y]\n");
c = getchar();
if (c == 'Y' || c == 'y') {
QUESTION question = parseQuestion(pData);
ask(&question);
free_choices(&question);
} else {
printf("Come back again.\n");
return 0;
}
} else {
printf("File failed to open.");
}
fclose(pData);
return 0;
}
Thank you to #alk how picked up my error, that is resolved.
What I still can't get is how to loop through the data file and populate the quiz structure with question structures.
So this is where I'm struggling at the moment. From what I can tell I'm pretty close to finishing this little program as long as I can get this to work.
parseQuestion() duplicates the choices but misses to duplicate the question as well as the answer.
Instead it simply copies the two arrays' addresses to the locally defined variable QUESTION q which is copied on return.
The memory for the question and answer strings is free'd on returning from the function, accessing it afterwards invokes undefined behaviuor.
i have built a small c program which i am trying to set a structure value
**static faut fautData**
typedef struct
{
char ds[25];
char ec[51];
char vc[51];
char rc[51];
char rb[2];
char eb[2];
char vb[2];
char es[10];
char dias[50];
char ss[10];
} faut;
i have a function name update to set values for the above specified structure
but when i try to set ** faut.es ** # the beginning of the update function the value does not get assigned(in my print call it does not get reflect.
when i set the same value # the end i i am able to print the output and see the value
why is that??
sample code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char ds[25];
char ec[51];
char vc[51];
char rc[51];
char rb[2];
char eb[2];
char vb[2];
char es[10];
char dias[50];
char ss[10];
} faut;
typedef struct
{
unsigned int d5;
unsigned int d10;
unsigned int d20;
unsigned int d50;
unsigned int d100;
unsigned int d500;
unsigned int d1000;
unsigned int an;
unsigned int rn;
unsigned int cn;
int alr;
}ncd;
static ncd chkncd;
int cdc;
void admin_init(void)
{
char Keys[17];
int i = 0;
int keysEnabled;
int shift = 0x01;
keysEnabled=0xFF;
strcpy(Keys,"0000000000000000");
//keysEnabled = getKeysToEnable();
for(i=0;i<8;i++)
{
switch((keysEnabled & shift))
{
case 0x10:
Keys[0]=0x34;
Keys[1]=0x36;
break;
case 0x20:
Keys[2]=0x34;
Keys[3]=0x37;
break;
case 0x40:
Keys[4]=0x34;
Keys[5]=0x38;
break;
case 0x80:
Keys[6]=0x34;
Keys[7]=0x39;
break;
case 0x08:
Keys[8]=0x34;
Keys[9]=0x34;
break;
case 0x04:
Keys[10]=0x34;
Keys[11]=0x33;
break;
case 0x02:
Keys[12]=0x34;
Keys[13]=0x32;
break;
case 0x01:
Keys[14]=0x34;
Keys[15]=0x31;
break;
default:
break;
}
shift = shift << 1;
}
printf("%s",Keys);
}
void update(void)
{
char temp[512];
int i = 0;
static faut fautData;
memset(&fautData, '\0', sizeof(fautData));
int cat =0;
if(cat) // Any failure
{
strncpy(fautData.ds, "3", 1);
strncpy(fautData.es, "4", 1);
memset(temp,'\0',sizeof(temp));
}
else
{
strncpy(fautData.es, "2",1);
strncpy(fautData.ds, "0",2);
}
strcpy(&fautData.ec[0],"00000000000000000000000000000000000000000000000000");//00000000000000000000000000000000000000000000000000
strcpy(&fautData.rc[0],"00000000000000000000000000000000000000000000000000");//00000000000000000000000000000000000000000000000000
strcpy(fautData.vc,"");
if(chkncd.d50 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"01");
sprintf(temp, "%03d", chkncd.d50);
strcat(fautData.vc,temp);
}
if(chkncd.d100 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"02");
sprintf(temp, "%03d", chkncd.d100);
strcat(fautData.vc,temp);
}
if(chkncd.d500 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"03");
sprintf(temp, "%03d", chkncd.d500);
strcat(fautData.vc,temp);
}
if(chkncd.d1000 != 0){
memset(temp,'\0',sizeof(temp));
strcat(fautData.vc,"04");
sprintf(temp, "%03d", chkncd.d1000);
strcat(fautData.vc,temp);
}
sprintf(fautData.vb, "%02d", chkncd.an);
fautData.rb[0] = 0x30;
fautData.rb[1] = 0x30;
fautData.eb[0] = 0x30;
fautData.eb[1] = 0x30;
strncpy(fautData.dias, "0", 1);
cdc = cdc - chkncd.an - chkncd.cn;
if ((chkncd.alr) || (cdc < 2450))
strncpy(fautData.ss, "4", 1);
else
strncpy(fautData.ss, "1", 1);
sprintf(temp,"keysEnabled:\nds : %s\nec : %s\n vc : %s\nrc : %s\n rb : %s\n eb : %s\n vb : %s\n es : %s\n ss : %s\n", fautData.ds, fautData.ec, fautData.vc, fautData.rc, fautData.rb, fautData.eb, fautData.vb, fautData.es, fautData.dias, fautData.ss);
printf("%s",temp);
}
int main(void) {
cdc=2300;
chkncd.d5=0;
chkncd.d10=0;
chkncd.d20=0;
chkncd.d50=0;
chkncd.d100=0;
chkncd.d500=1;
chkncd.d1000=0;
chkncd.alr=0;
chkncd.an=1;
chkncd.rn=0;
chkncd.cn=0;
update();
return EXIT_SUCCESS;
}
Your problem is here:
sprintf(fautData.vb, "%02d", chkncd.an);
fautData.vb is two bytes, but your sprintf call will write three bytes: the two-digit number followed by a null terminator, which overflows the vb array and overwrites fautData.es.
When you do
strncpy(fautData.es, "2",1);
you are copying "at most 1 character". This leaves you without the terminating null, and that can cause a problem. As the description says:
No null-character is implicitly appended at the end of destination if
source is longer than num. Thus, in this case, destination shall not
be considered a null terminated C string (reading it as such would
overflow).
You need to do
strncpy(fautData.es, "2",2);
to make sure you have a valid string.
Further, in your line
sprintf(fautData.vb, "%02d", chkncd.an);
You are putting a '\0' after .vb (so really you are writing three characters in total). But since vb only has space for two characters, the nul will be put as the first element of the next structure element - which happens to be .es. Thus, when you try to print .es, the first character is "end of string", and nothing gets printed.
If you change the struct to have three elements of space for vb:
char vb[3];
the problem goes away.
This is a tricky thing that happens all the time; you need one more space for each string than you have "characters". That '\0' takes space...
update as you said that you are constrained to have two bytes, you have to limit yourself to printing just two characters to the structure element during writing - and you have to limit yourself to printing only two characters during printing. Example:
void set_vb(int value) {
char temp[3];
sprintf(temp, "%02d", value);
memcpy(fautData.vb, temp, 2);
}
void print_vb(void {
printf("%.2s", fautData.vb);
}
Now you can forget "how to do it right", and just call these two functions when you need to set or print the value of vb. You could do the same for other elements where you run into this issue (given the tight size of your struct, that could apply to many of them...)