I cannot understand what's wrong with my c implementation of: dynamically allocating an array of struct inside a function to use with in other functions.
The problem is my .exe stops working after reading the first struct(which is read correctly).
The struct:
struct student
{
char name1[30], name2[30];
float grade;
};
The function:
void read(int *n, struct student **a)
{
if(scanf(" %d", n) == 1)
{
int i;
*a=(struct student*)malloc((*n)*sizeof(struct student*));
for(i=0; i<*n; i++)
scanf("%29s %29s %f",(*a)[i].name1, (*a)[i].name2, &(*a)[i].grade);
//it stops working right after this line is executed
}
}
Main:
int main()
{
int n;
struct student *a;
read(&n, &a);
return 0;
}
Warrnings:
format '%s' expects argument of type 'char *', but argument 2 has type 'char (*)[30]' [-Wformat=]|
format '%s' expects argument of type 'char *', but argument 3 has type 'char (*)[30]' [-Wformat=]|
Using a+i instead of a[i] doesn't change anything. I am aware &(*a) means a, but i wanted to make everything as clear as possible. I feel like there's something obviously wrong about my dynamic allocation that i'm missing. I read so many questions here, but nothing appears to solve my problem. Thanks for your time!
EDIT 1: i changed the code to the suggestions:
scanf("%29s %29s %f", a[i].name1, a[i].name2, a[i].grade);
and now i get the error below instead.
Error:
error: request for member 'name1' in something not a structure or union
EDIT 2: so, the line:
scanf("%29s %29s %f",*a[i].name1, *a[i].name2, *a[i].grade);
gives the error:
request for member 'name1' in something not a structure or union
and the line:
scanf("%29s %29s %f",(*a)[i].name1, (*a)[i].name2, (*a)[i].grade);
crashes.
EDIT 3:
scanf("%29s %29s %f", (*a)[i].name1, (*a)[i].name2, &(*a)[i].grade);
works.
Here
*a=(struct student*)malloc((*n)*sizeof(struct student*));
^^^^^
you allocate space for *n pointers to struct student but it seems that you really want to allocate space for *n struct student.
It seems you want:
*a=malloc((*n)*sizeof(struct student));
Also notice that *a[i] is the same as *(a[i]) but you probably want (*a)[i]. So you need something like:
scanf("%29s %29s %f", (*a)[i].name1, (*a)[i].name2, &(*a)[i].grade);
Notice that you need & in front of (*a)[i].grade but not the other two places because the two two other are arrays.
As mention by #unwind in a comment: The scanf is wrong
This
scanf("%d",&(*n));
should be
scanf("%d", n);
and then you should also check the return value, like
if (scanf("%d", n) != 1)
{
// Add error handling here
....
}
Related
I have a problem with a small project, I have to create a structure containing a person's data,I have to do data entry via a function using pointers.
I don't understand why when I try to enter the weight the program ends with this error:
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
I made an example of the code that is giving me problems:
typedef struct{
char name[DIM];
char surname[DIM];
int height;
float weight;
}Record;
int main() {
Record subj;
insRecord(&subj);
}
void insRecord(Record *subj){
printf("\nName ");
scanf("%64[^\n]s", subj->name);
cleanBuffer();
printf("\nSurname ");
scanf("%64[^\n]s", subj->surname);
cleanBuffer();
printf("\nEight ");
scanf("%3s", subj->height);
cleanBuffer();
printf("\nWeight ");
scanf("%6s", subj->weight);
cleanBuffer();
}
int cleanBuffer(){
int cont= 0;
char c;
do{
cont++;
c = getchar();
}while(c != '\n');
return cont;
}
(I only wrote the main functions).
Furthermore, compiler is giving warnings on height and weight scanf() statements:
Format specifies type 'char *' but the argument has type 'int' (for height)
Format specifies type 'char *' but the argument has type 'double' (for weight)
Could you tell me how can I solve?
PS the project is divided into several files (3 files).
In main.c I wrote the insRecord() function, in struct.h I wrote the Record structure, in struct.c I wrote cleanBuffer() function.
You are reading a string (%s) and try to store that in a float. If you use the flag %f for weight and %d for height it will probably work better. Remember that you should provide a pointer to the float and int that you want to store the data in, you are not doing that in your example.
Have a look at the scanf documentation:
https://www.tutorialspoint.com/c_standard_library/c_function_scanf.htm
Good luck
The following code passes an array as a parameter from a process of main (called process) into another process (called subprocess). It simulates behavior I want to achieve in code of my own: subprocess fills a string array with the correct strings and then returns them to process for... processing.
#include <stdio.h>
#include <string.h>
void preprocess(char input[10][10]) {
int i;
char temp[10];
for (i = 0; i < 10; i++) {
scanf("%s", &temp);
strcpy(input[i], temp);
}
}
void process() {
int i;
char strings[10][10];
preprocess(strings);
for (i = 0; i < 10; i++) {
printf("%s\n", strings[i]);
}
}
int main() {
process();
return 0;
}
My question: this code generates a warning and I'm not 100% sure about it. Can someone help me remove the warning and clear this code of booby traps?
EDIT: The warning was:
warning: format '%s' expects argument of type 'char *', but argument 2 has type 'char (*)[10]'
The parameter you pass in to scanf is incorrect. The %s format specifier expects a pointer to the first element of an array of char. What you're passing in is the address of the array.
Remove the address-of operator & from the scanf call. When an array is passed to a function, it decays to a pointer to the first element.
scanf("%9s", temp);
The number in the format specifier gives the maximum number of characters to be read. This prevent a potential buffer overflow of temp.
You should use:
scanf("%s", temp);
not
scanf("%s", &temp);
I'm having problems with a function that I use to write to an element of an array.
I think it might be because I'm not passing the array of struct correctly. I was wondering if someone can point out how to do this correctly. I've been screwing it up more than fixing it.
let's say I have a function menu.c
I declare my struct newPerson person[MAX_PERSONS];
I then run my function addPerson(person, &num);
which is the following
void addPerson(newPerson *pers, int *num){
pers[*num] = (newPerson) {
"Michelle", "Leo", "6136458798", STUDENT,
.data = {.s = {9, 1234.50, 3}}
};
*num = *num + 1;
}
It runs, but won't print out correctly, I'm guessing because it doesn't write where I want it to pers[num]. I tried calling the function this way also addPerson(&person, &num); instead of just addPerson(person, &num); but then I receive this error
warning: passing argument 1 of ‘addPerson’ from incompatible pointer type [enabled by default]
and
note: expected ‘struct newPerson ’ but argument is of type ‘struct newPerson ()[20]’
I've tried changing the function to void addPerson(newPerson *pers[], int *num){ as well but nothing there. Was wondering if anyone can point out what I'm doing wrong here and how I can fix my problem. Any help would be appreciated, thanks!
Forgot to mention that the addPerson function works in some places where I run it.
int menu(int num) {
newPerson person[MAX_PERSONS];
//printf("THE NUMBER START OF MENU IS %d\n", num); test counter
//addPerson(person, &num); <- WRITES AND READS PROPERLY IF DONE HERE
int option;
printf(
"\n\tPlease choose one of the following options to continue (0-9): ");
scanf("%d", &option);
if (option == 1) { //program will ask for name input
addPerson(person, &num); <- HOWEVER IT DOES NOT WRITE OR READ PROPERLY HERE
menu(num);
}
Both functions are called in menu.c
However when I call addPerson in the if statement, it does not write/read properly.
Just solved the problem by declaring the struct as static!
static newPerson person[MAX_PERSONS];
I'm not sure if this is taboo or anything, but it fixed my problem!
By making static you have made the code inefficient as the memory for
the data structure has been set aside regardless of whether it is
needed or not while the program is executing.(With a static data
structure, the size of the structure is fixed.)
Declare the function like
void addPerson(newPerson *pers[],int *num)
call the function like
void addPerson(newPerson *pers, int *num);
OR
void addPerson(newPerson pers[], int *num);
I was able to get it working by declaring the struct as static
static newPerson person[MAX_PERSONS];
Not sure if this is an actual fix or if it's just masking my problem though.
I'm working on my assignment for my C course, and I'm trying to take in the user's input and store it in a variable to use for later in my code. Here's what my main function looks like,
int main() {
// Variables here
char* inputLine[10];
do {
printf("Insert number....");
scanf("%s\n", inputLine);
// More stuff here
}
return 0;
}
This code gives me a bunch of warnings, warning: format specifies type 'char *' but the argument has type 'char **' [-Wformat], and if I change the variable declaration to,
char* inputLine = NULL;
When I execute my code I get a seg fault, can someone explain to me what I am doing wrong, and the differences of what happens in the memory when I'm initializing this variable?
char* inputLine[10];
--> is an array of ten pointers to char
printf's format %s expects argument of type char *, but you're providing it as type char **
Just use
char inputLine[10];
To avoid possible buffer overflow you should use
scanf("%9s", inputLine); //Notice the size with %s
9 only because C string are null terminated ('\0') so one extra byte for it goes at end
char inputLine[10];
do {
printf("Insert number....");
scanf("%9s\n", inputLine);
// More stuff here
} while( //some condition);
However if you edit your code and remove * you get answer, but normal array deprecated, nowdays, programmers use vector, normal array in C not safe :
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<string> inputLine;
You can define with every data type:
vector<int> myvar;
Or you can define multidimensional vector:
vector< vector <int> > myvar;
Here is my main function:
main(){
int *seats[50] = {0};
char x;
do{
printf("A-Add Reservation\tC-Cancel Reservation\n");
scanf("%c", &x);
} while(x != 'a' && x != 'c');
switch(x){
case 'a':
addRes(&seats);
break;
default:
break;
}
}
I am trying to pass seats[] into the addRes() function so I can modify it within addRes(). Here is the function:
void addRes(int **seats[]){
int s, i, scount=0, j=0, k=0, yourseats[]={0};
printf("How many seats do you require? ");
scanf("%i\n", &s);
for(i=0;i<=sizeof(*seats);i++){
if(*seats[i] == 0)
scount++;
}
if(scount >= s){
for(i=0;i<=s;){
if(*seats[i] == 0){
yourseats[j]=i;
*seats[i]=1;
i++; j++;
}
else i++;
}
printf("Your seat numbers are: \n");
while(k < j){
printf("%i\n", yourseats[k]);
k++;
}
}
else {
printf("Sorry, there are not enough seats available.\n");
}
}
It compiles with the warnings:
Line 15 (*seats[i]=1;) Assignment makes pointer from integer without a cast.
Line 53: (addRes(&seats);) Passing argument 1 of 'addRes' from incompatible pointer type.
Line 3: (void addRes(int ** seats[]){) Expected 'int ***' but argument is of type 'int *(*)[50]'.
On running the program it gets to
How many seats do you require?
and does nothing after entering a value.
Any help would be much appreciated!
Declaration int **seats[] in function parameter is == int ***seats, and this means type of *seats[i] is int* and you are assigning a number to it, that is incompatible type error:
*seats[i] = 1;
^ ^ int
|
int*
incompatible types
Next in addRes(&seats);
seats in array of pointer its type if int*[50] that &seat is pointer of array and type of &seat is int*(*)[50] Where as function argument type is int ***, so again type incompatible error.
Notice you are also getting a reasonable error message from compiler: Expected 'int ***' but argument is of type 'int * (*)[50]'.
Suggestion:
As I can see in your code, you don't allocate memory for seats[i] in your function addRes() and So as I understand you not need to declare seat[] array as array of pointers but you need simple array of int.
Change declaration in main():
int *seats[50] = {0};
should be just:
int seats[50] = {0};
// removed * before seats
Next just pass seats[] array's name to addRes() function where declaration of function should be
addRes(int* seats)
or addRes(int seats[])
it make your work pretty simple in function addRes() you can access its elements as seats[i] ( and it no need to use extra * operator).
Length of array:
One more conceptional problem in your code that you are using sizeof(*seats) to know the length of array. Its wrong! because in addRes() function seats is not more an array but a pointer so it will give you the size of address ( but not array length).
And yes to inform about size of seats[] in addRes() function send an extra parameter called length, so finally declare addRes() as follows (read comments):
void addRes(int seats[], int length){
// access seat as
// seat[i] = 10;
// where i < length
}
Call this function from main() as follows:
addRes(seats, 50);
// no need to use &
One more problem that presently you are not facing but you will encounter soon as you will run you code that scanf() need extra enter in function addRes(). To resolve it change: scanf("%i\n", &s); as scanf("%i", &s); no need of extra \n in format string in scanf().
int *seats[50] = {0};
This is an array of integer pointers, all you need is an actual array so drop the * resulting in int seats[50] = {0};.
Also your function signature for an array is wrong, void addRes(int seats[]) will do fine.
Finally, to pass an array to that new signature, you can pass the array directly without any unary address-of operators (arrays will decay to a pointer when passed as an argument to a function):
addRes(seats);
Also as pointed out, when assigning to an array element, you need to drop the *:
seats[i]=1;
Is more than enough. Same goes for the if statements and the like where you do a comparison against an array element.
Regarding your addRes function:
for(i=0;i<=sizeof(*seats);i++)
You will only get the size of the pointer this way, which on a 32bit machine is 4. This trick will not work on an array passed to a function. You will need to pass the array separately.
You can fix it in the following way:
Change the function signature of address to this:
void addRes(int seats[], int size)
Pass the size in one of the following ways in main:
Directly: addRes(seats, 50);
Indirectly: addRes(seats, sizeof(seats)/sizeof(int));
Note that the above only works on local to the scope of this function arrays, it won't work on an array you've obtained as an argument to a function (or dynamically allocated arrays).
Another issue is to do with scanf, you should drop the \n. Use scanf("%i", &s);