Input and output array don't match - c

I am writing a program for a class at school and I cannot get the program to print out what I type in.
The problem states that the first line needs to contain the number of questions on an 'exam' followed by a space then the answer key. I wanted to print the answer key to make sure that it was being entered in correctly and it never matches what I type in. The code is posted below.
This is the main file that starts being run and it calls a method from another file I have made the prototype file correctly so I'm pretty sure it's not that.
int main()
{
int i;
int noOfQuestions;
scanf("%d ", &noOfQuestions);
char * answerKeyPtr;
answerKeyPtr = fgetAnswers(noOfQuestions);
for(i = 0; i < noOfQuestions; i++){
printf("%c",answerKeyPtr[i]);
}
printf("\n");
return 0;
}
char *fgetAnswers(int noOfQuestions){
int i;
char * answerKeyPtr;
char AnswerKey[noOfQuestions];
answerKeyPtr = AnswerKey;
for(i = 0; i < noOfQuestions; i++){
scanf("%c",&AnswerKey[i]);
}
return answerKeyPtr;
}

What you have here is a memory problem.
You're storing data into the AnswerKey array, which is local to fgetAnswers(). The problem is you're returning a pointer to that local variable, and that variable's memory is not reliable as soon as your fgetAnswers() function finishes that memory should not be accessed. So when you try to print the data in main() you're accessing memory you shouldn't.
To solve it, create the AnswersKey array in main, and pass it as a parameter to the fgetAnswers() function.

The char array AnswerKey is allocated on the stack when fgetAnswers is called. When you return from fgetAnswers, data stored in the stack frame for that call is no longer valid. You'll need to pass in the array or alloc it so the input isn't stored in the stack.

Related

How to initialize these pointers?

I need to make a list of employees and I can't change these structures, I'm having trouble in how to initialize each of tab[10] to NULL and how to set values
#include <stdio.h>
#include <stdlib.h>
typedef struct employee Employee;
struct employee{
char name[81];
float salary;
};
Employee *tab[10]; /*a table with employee*/
void set(Employee **tab, int i, char *name, float salary){
tab[i]->name = name;
tab[i]->salary = salary;
}
int main(){
Employee *e;
int i = 0;
for(; i < 10; i++) init(i,&e);
return 0;
}
/*a table with an employee, each position must have a name and a salary*/
Employee *tab[10];
void init(int n, Employee **tab);
Everaldo
With commentators helping you, it seems you are getting there. I would like to sum up the suggests given so far and add a couple of my own.
Declaring the Employee array
Declaring the array as a global variable and then passing it as a parameter to functions makes things a little confusing. I usually prefer declaring a local variable and then passing it to the various functions that uses it. Also as suggested by David C. Rankin, to initialize every array element to 0 just requires you to initial the first element in the declaration statement. No FOR loop needed. The compiler will auto initialize the rest of the array elements for you.
main()
{
Employee* tab[10] = { NULL };
. . . .
}
Array memory allocation
As mention by Patrick87, you need to add code to assign memory to every element in the array. An example initialization routine could be coded as follows:
int init(int len, Employee** tab) {
int i = 0;
for (i = 0; i < len; i++)
{
if ( (tab[i] = (Employee*) calloc (1,sizeof(Employee))) == NULL )
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Function usage:
if (init(10, &tab) == EXIT_FAILURE)
{
puts("CALLOC Failed, aborting....");
exit(EXIT_FAILURE);
}
Things to note:
Check to ensure the memory was allocated. On failure return some
type of failure status to alert the caller of the function.
The status codes that are being returned are define in stdlib.h.
They are not necessary but do give a clear indication to the reader
of your code the success and failure paths your code takes.
The FOR loop was moved inside the initialization function. Function
calls are expensive when it comes to processing time. Since the
array size is known, it is faster to perform the loop inside the
function.
Try to always write functions that return a status. This will enable
the caller to perform any error handling if the function's operations
fail.
Set array element values
The following statement is not valid. You cannot directly copy the content from a string pointer to an array of characters. You will need to use statements like strcpy, strncpy, or memcpy to copy the data.
tab[i]->name = name;
There is a method I prefer for copying strings.
sprintf(tab[i]->name, "%.80s", name);
This will copy up to 80 characters from name into tab[i]->name, then insert a null character. The beauty of this statement is that the designation variable does not have to be the same size as the source. If the source variable (in this case name) is shorter, spirntf will simply stop when it encounter a null character and then null terminate the destination string. If the source is longer than 80 characters or if it is missing the null terminator character, sprintf will stop coping at the 80st character position and then auto insert a null character in the 81st character position.
An example SET routine could look like the following:
void set(Employee** tab, int i, char* name, float salary) {
sprintf(tab[i]->name, "%.80s", name);
tab[i]->salary = salary;
}
Usage:
for (i = 0; i < 10; i++)
{
set(&tab, i, "Bob", 35000. + i); // bogus values, demo purposes only
}
Main program logic
Your main program as you currently have outline will need to change. For starters, the declaration of variable “e” should be replace with the declaration of variable “tab” (see Patrick87 comments) . On initializing the array, see my suggestion above. To set values to the array elements see SET function comments above.
Free memory
Every time you allocate memory, you must free it when you are done. Forgetting to free allocated memory will create memory leaks in your program. Note technically, in this demonstration program, the system will free the memory when your code exits, so you do not need to free it. But it is good practice so when you start writing real applications you will not forget to do so.
Here is an example on how this could be done:
for (i = 0; i < 10; i++)
free (tab[i]);
tab is an array of pointers, so to initialize them all to NULL, you can use a for loop, e.g.
for (i = 0; i < n; i++)
tab[i] = 0;
To set a value, allocate some space for an instance of your struct (either on the stack via function parameter or local variable, or else on the heap by with malloc/calloc/realloc) and then set one of the tab[k] to the address of the memory you allocated (using & or just the pointer directly if allocated).

printing strings produces garbage even when (I think) they are null terminated

When I run print_puzzle(create_puzzle(input)), I get a bunch of gobbledegook at the bottom of the output, only in the last row. I have no idea why this keeps happening. The output is supposed to be 9 rows of 9 numbers (the input is a sudoku puzzle with zeroes representing empty spaces).
This bunch of code should take that input, make a 2d array of strings and then, with print_puzzle, print those strings out in a grid. They are string because eventually I will implement a way to display all the values the square could possibly be. But for now, when I print it out, things are screwed up. I even tried putting the null value in every single element of all 81 strings but it still get's screwed up when it goes to print the strings. I'm lost!
typedef struct square {
char vals[10]; // string of possible values
} square_t;
typedef struct puzzle {
square_t squares[9][9];
} puzzle_t;
static puzzle_t *create_puzzle(unsigned char vals[9][9]) {
puzzle_t puz;
puzzle_t *p = &puz;
int i, j, k, valnum;
for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
puz.squares[i][j].vals[0] = '\0';
puz.squares[i][j].vals[1] = '\0';
puz.squares[i][j].vals[2] = '\0';
puz.squares[i][j].vals[3] = '\0';
puz.squares[i][j].vals[4] = '\0';
puz.squares[i][j].vals[5] = '\0';
puz.squares[i][j].vals[6] = '\0';
puz.squares[i][j].vals[7] = '\0';
puz.squares[i][j].vals[8] = '\0';
puz.squares[i][j].vals[9] = '\0';
valnum = vals[i][j] -'0';
for (k = 0; k < 10; k++){
if ((char)(k + '0') == (char)(valnum + '0')){
char tmpStr[2] = {(char)(valnum +'0'),'\0'};
strcat(puz.squares[i][j].vals, tmpStr);
}
}
}
}
return p;
}
void print_puzzle(puzzle_t *p) {
int i, j;
for (i=0; i<9; i++) {
for (j=0; j<9; j++) {
printf(" %2s", p->squares[i][j].vals);
}
printf("\n");
}
}
In short:
In function create_puzzle(), you are returning a pointer to the local variable puz. Local variables are only known to function inside their own. So the content referenced by the pointer returned by create_puzzle is indeterminate.
More details:
In C++, local variables are usually generated as storage on a "stack" data structure. when create_puzzle() method is entered, its local variables come alive. A function's local variables will be dead when the method is over. An implementation of C++ is not required to leave the garbage you left on the stack untouched so that you can access it's original content. C++ is not a safe language, implementations let you make mistake and get away with it. Other memory-safe languages solve this problem by restricting your power. For example in C# you can take the address of a local, but the language is cleverly designed so that it is impossible to use it after the lifetime of the local ends.
This answer is very awesome:
Can a local variable's memory be accessed outside its scope?
In function create_puzzle(), you are returning a pointer of the type puzzle_t. But, the address of variable puz of the type puzzle_t is invalid once you return from the function.
Variables that are declared inside a function are local variables. They can be used only by statements that are inside that function. These Local variables are not known to functions outside their own, so returning an address of a local variable doesn't make sense as when the function returns, the local storage it was using on the stack is considered invalid by the program, though it may not get cleared right away. Logically, the value at puz is indeterminate, and accessing it results in undefined behavior.
You can make puz a global variable, and use it the way you are doing right now.
You are returning a local variable here:
return p;
Declare p and puz outside of the function, then it should work.
p point to local memory that is unavailable after the function ends. Returning that leads to problems. Instead allocate memory.
// puzzle_t puz;
// puzzle_t *p = &puz;
puzzle_t *p = malloc(sizeof *p);
assert(p);
Be sure to free() the memory after the calling code completes using it.

Why will this not print?

Before you feel the need to mark this as a duplicate post, please don't. I have read all the threads on pointers, arrays, and functions I could find but almost all of them are far too advanced to be of any help to me.
I'm not getting an error, however my code will not print my array. It seems the issue here is using scanf. I don't think the values entered are actually being put into the array in main(). I've tried using pointers, but then I get the error "Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)" whenever I try to use scanf to collect user inputted values to put into the array.
What I am working on is limited to declaring my array in the main() function, but all the operations are to be performed in promptData() function. Any help would be great, I'm at my wits end trying to figure this out on my own.
#import <stdio.h>
void promptData(double data[], int numElem);
int main(int argc, const char * argv[])
{
int size, i;
double array[size];
promptData(array, size);
for (i = 0; i < size; i++)
printf("%.2lf\n", array[i]);
return 0;
}
void promptData(double data[], int numElem)
{
int i;
printf("Enter integer values for size of array.\n");
scanf("%i", &numElem);
for (i = 0; i < numElem; i++)
{
printf("Enter array values.\n");
scanf("%lf", &data[i]);
}
}
Your program has undefined behaviour because variable size was not initialized and has indeterminate value.
You should at first in main ask the user to enter the size of the array then define the array itself and only after that fill it with values.
For example
int main(int argc, const char * argv[])
{
int size = 0;
printf( "Enter a positive integer value for the size of the array: ");
scanf( "%i", &size);
if ( size == 0 ) exit( 1 );
double array[size];
promptData(array, size);
//...
Also in C there is no such a directive as
#import <stdio.h>
Use instead
#include <stdio.h>
At least in ANSI C 89 and C 90, you can't give a variable as the size of an array. The size of array should be known at compile time. You should be doing something like double array[size];.
Even in C99, where you can have variable sized arrays; the variables should contain proper index values at the time you declare the array. In that case, you should read the number from stdin and then declare the array.
Also in C, all parameters are passed by value. This means every function takes a copy of the parameters in the function. If you want to modify a variable's value, you should pass a pointer to it, and then modify the pointer's dereferenced value, something like:
void change(int *x)
{
*x = 7;
}
void first(void)
{
int x = 5;
change(&x);
printf("%d\n", x);
}
Adding on to the other, correct, answer by Zenith, if you want a dynamically allocated array (like you want to be able to change its size based on user input), then your only option is to use one of the memory allocation functions like malloc().
Once you actually have the size in your main function, declare your array like this:
int *myArray = malloc(sizeof(int) * size));//note that malloc will return a NULL if it fails
//you should always check
if(myArray != null) {
//do stuff with myArray like you were. You can just use myArray[] as long as you
//make SURE that you don't go beyond 'size'
}
free(myArray);
//VERY important that every malloc() has a free() with it
Note: untested, but the idea is there.
Further, to answer your other question.
If you find yourself in a situation where you need to call a function and use things INSIDE that function to change stuff where you called it, you have only two choices in C.
You can either return the value and assign it to a variable in the calling function like this:
int result = myFunction(someVariable, anotherVariable);
//do stuff with result
Or, use pointers.
I'm not explaining pointers here, that's usually several lectures worth of information, and is one of the more difficult concepts to grasp for introductory programmers. All I can tell you is you need to learn them, but this format is not the right way to go about doing that.
You're passing size to promptData as a copy.
Thus changes to numElem inside promptData will not affect the size variable in your main. Hence size remains uninitialized, i.e. has an undefined value and therefore should not be used as a size for an array.
If you need to initialize an array with a size that's only known at run-time, you need to allocate memory for the array dynamically using malloc, for example:
double* array = malloc(size * sizeof(double));

Why will this code not print the list of items? I know its to do with return

I know it should return a value to the main function but do not know how to output the list without doing it in the main function.
I want to be able to call the menu function and it print the list of items to the screen
#include <stdio.h>
int main()
{
int menu;
return 0;
};
int Menu (const char *Items[3], int Price [], int NoItems )
{
int i;
//assigning values to arrays
Items[1] = "lamp";
Items[2] = "Toothbrush";
Items[3] = "Battery";
Price[1] = 4.5;
Price[2] = 3.68;
Price[3] = 0.99;
for(i=1; i<4; i++)
{
printf("1) %s: %d\n",Items[i], Price[i]);
}
return 0 ;
}
The reason you aren't getting any output...
The compiler makes the resulting executable so that it starts with main. Since main does not call the function with your output, Menu, it doesn't get called at all.
It appears from that you have Menu after main that you are trying to have it execute last. To do this, you could simply have it as the last call in main, or you could use atexit(Menu); to have it called upon exit (even if the program is terminated early, such as with a call to exit).
Also the people in the comments of your post are right - the indices ([...]) don't make much sense. They are technically valid but depending on your usage you may get a memory access violation due to buffer overflow (trying to access memory beyond what is allocated for the array will give you junk data or, more likely, will crash your application entirely, immediately if the OS or hardware detects that the program is trying to use memory it doesn't own, or later on if you broke the stack by writing something to it).
You can put the variable initializer int i = 0; in the for loop itself.
You are using ints for the Price values, but assigning them non-integers. They will be truncated (made into whole numbers) in this case. Instead, I recommend you use floats which retain the more precise values you put in them.
It's not necessary to return a value from Menu unless it provides something not constant. Since it's just returning 0, you are wasting 4 bytes of memory to have something that always equals 0.
Since Menu is declared after main, in which it is called, you must either 1. Provide a function prototype (which I have demonstrated below) or 2. Move the function itself to before any places where it is called.
I assume that where you have "1)" in your output you mean to show the number of each item in the list. If you want this to change as you step through your list, you need to not always have it "1)" but rather use an escape character and provide a variable.
To put this all together...
#include <stdio.h>
void Menu (const char**, float*); // Prototype
int main()
{
const char* Items [3];
float Price [3];
Menu(Items,Price);
return 0;
};
void Menu (const char *Items [3], float Price [3])
{
Items[0] = "Lamp";
Items[1] = "Toothbrush";
Items[2] = "Battery";
Price[0] = 4.5;
Price[1] = 3.68;
Price[2] = 0.99;
for(int i = 0; i < 3; i++) printf("%d) %s: %f\n", i + 1, Items[i], Price[i]);
};

C pass size of an array to another c file variable

**Issue overview **
The current issue i have is that i have an array which has the size of a variable which happens to be the amount of lines in a file. This is an integer which is calculated and returned, which becomes the arraysize (e.g. file text.txt has 12 lines so the array is of size 12).
I want to know how i can return this value to another c file for use in a function so i can loop through the complete array.
points to note
I am not allowed any globals at all in this assignment, no global arrays/variables at all.
The line counting functions works correctly so i will not be posting it here
The array is set up correctly and print the correct results
Most of the code from the functions has been removed to make it easier to read.
The correct #includes for each file are present, i just need an example of how to do it.
The code:
void read_from_file() {
/* reading and parsing removed */
no_of_lines = (count_lines(locof) - 1);
/* locof is a char array storing the file name */
ship ships[no_of_lines];
/* i want to return the value of no_of_lines *?
I want to return the value of no_of_lines
The c file where i need the value
/*This is where i need the variable */
void asign_mayday_to_ships() {
int* ship_arr_length = SIZE OF SHIP ARRAY NEEDED
mayday_call* mday_ptr;
ship* ship_ptr; /* this is a ship array */
mday_ptr = read_mayday_file();
ship_ptr = read_ship_locations();
int i;
for(i = 0; i < SIZE OF SHIP ARRAY; i++){
}
Just pass both pointer and size, it'a a C way.
void read_from_file() {
/* reading and parsing removed */
no_of_lines = (count_lines(locof) - 1);
/* locof is a char array storing the file name */
ship ships[no_of_lines];
some_fun_from_second_file(ships, no_of_lines);
Who calls the two fnctions? Can't you just return the nr of lines in an upper function then pass it in the second one? If not, then you must somehow store it in a variable(or a struct member) and then you can grab it later. This is a contextual solution, it might not work for you.
i had to first malloc my ships array, then set the size of the malloc depending on the amount of elements then i can return the size of the pointer:
ship* ships;
ships = malloc(sizeof (ship) * no_of_lines);
the in the function i was having trouble with:
mayday_call* mday_ptr;
ship* ship_ptr;
mday_ptr = read_mayday_file();
ship_ptr = read_ship_locations();
int arr_size = sizeof (ship_ptr) ;
int i;
for(i =0; i < arr_size; i++) {
//do something
}
`
sounds like your 'teacher' wants make you use a sentinel value. Ie put an object at the end of the array that cannot exist (a ship with name all spaces for example) then in the array processing you keep looping till you hit the magic value.
This is a bad design, but if you aren't allow globals and you aren't allow parameters I cant see what else to do

Resources