Accepting string from user in an array of pointers in C us - arrays

The code tries to get names of 3 students and their marks in 3 subjects and print total score as well as average of score of each student along with their names.
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
int main() {
char *names[3];
int test1[3],test2[3],test3[3];
for(int i=0;i<3;i++)
{
scanf("%s",&(*(names+i)));
scanf("%d",&test1[i]);
scanf("%d",&test2[i]);
scanf("%d",&test3[i]);
}
int j=0;
while(j<3){
printf("%s",*(names+j));
printf(" %d ",test1[j]+test2[j]+test3[j]);
printf("%.f\n",(test1[j]+test2[j]+test3[j])/3.0);
j++;
}
return 0;
}
But when I run this code, I am not getting output of any of the printf's written in while loop . Can anyone help me please?

The variable names is an array of pointers. But you never make these pointers actually point anywhere. Any attempt to dereference them will lead to undefined behavior.
Also the type of &names[i] (which is what &(*(names+i)) really is) is char **, which is not what the scanf format %s expects. Mismatching format specifier and argument type also leads to undefined behavior.
What you should use is an array of arrays of characters:
char names[3][256];
and let the sub-arrays decays to pointers to their first element (the expression names[i] decays to &names[i][0] which have the type char *):
scanf("%255s", names[i]);
Note that I added a length specifier to avoid writing out of bounds of names[i].
Then print as a normal string:
printf("%s %d %f\n", names[j],
test1[j] + test2[j] + test3[j],
(test1[j] + test2[j] + test3[j]) / 3.0);

For starters you included too many headers.
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
Actually only declarations from the header <stdio.h> are used in the program. So remove all other headers and leave only the header <stdio.h>
#include <stdio.h>
In this declaration
char *names[3];
there is declare an uninitialized array of pointers that have indeterminate values.
So this call of scanf
scanf("%s",&(*(names+i)));
that should be written at least like
scanf("%s",*(names+i));
because the expression &(*(names+i)) has the type char ** but the function expects an argument of the type char * invokes undefined behavior.
To store strings you need to declare an array of character arrays as for example
char names[3][100];
But in any case your approach with declaring four arrays looks is not good.
It will be better to declare a structure as for example
enum { NumberOfStudents = 3, NumberOfMarks = 3, MaxNameLen = 100 };
struct Student
{
char name[MaxNameLen];
unsigned int marks[NumberOfMarks];
};
In this case you could declare only one array of three object of the type struct Student.
Here is a demonstration program
#include <stdio.h>
int main( void )
{
enum { NumberOfStudents = 3, NumberOfMarks = 3, MaxNameLen = 100 };
struct Student
{
char name[MaxNameLen];
unsigned int marks[NumberOfMarks];
};
struct Student students[NumberOfStudents];
printf( "Enter information about %d srudents.\n", NumberOfStudents );
for (int i = 0; i < NumberOfStudents; i++)
{
printf( "Name of student #%d: ", i + 1 );
scanf( "%99s", students[i].name );
printf( "Enter his %d marks: ", NumberOfMarks );
for (int j = 0; j < NumberOfMarks; j++)
{
scanf( "%u", &students[i].marks[j] );
}
}
puts( "\nHere are the students with their total and average marks." );
for (int i = 0; i < NumberOfStudents; i++)
{
printf( "%s: ", students[i].name );
unsigned total = 0;
for (int j = 0; j < NumberOfMarks; j++)
{
total += students[i].marks[j];
}
printf( "%u %.1f\n", total, ( double )total / NumberOfMarks );
}
}
The program output might look like
Enter information about 3 srudents.
Name of student #1: Tom
Enter his 3 marks: 4 5 3
Name of student #2: Mary
Enter his 3 marks: 5 5 4
Name of student #3: Bob
Enter his 3 marks: 6 6 4
Here are the students with their total and average marks.
Tom: 12 4.0
Mary: 14 4.7
Bob: 16 5.3

Related

How to Print an array with names

I wrote this code to input names to array (eg:Jon,raj...) and the input part is ok but how to print exact name that i input to this array a[5] why this code is not working
#include <stdlib.h>
#include<stdio.h>
int main(){
int i;
char a[5];
for(i=0;i<5;i++){
printf("Enter ");
scanf("%s",&a[i]);
}
for(i=0;i<5;i++){
printf("%s \n",a[i]);
}
}
Your array a is an array of chars. This means that in each position you will have only one char.
You can do this any one of these two ways:
Pre-allocated (array of arrays of chars)
#include <stdio.h>
int main(){
const int NAME_MAXIMUM_SIZE = 50;
const int NUMBER_OF_NAMES = 5;
int index;
char names [NUMBER_OF_NAMES][NAME_MAXIMUM_SIZE];
for(index=0; index<NUMBER_OF_NAMES; index++){
printf("Enter ");
scanf("%49s",names[index]);
}
for(index=0; index<NUMBER_OF_NAMES; index++){
printf("%s \n",names[index]);
}
}
Malloc + free (array of pointers)
#include <stdio.h>
#include <stdlib.h>
int main(){
const int NAME_MAXIMUM_SIZE = 50;
const int NUMBER_OF_NAMES = 5;
int index;
char *names [NUMBER_OF_NAMES];
for(index=0; index<NUMBER_OF_NAMES; index++){
names[index] = (char*)malloc(NAME_MAXIMUM_SIZE);
printf("Enter ");
scanf("%49s",names[index]);
}
for(index=0; index<NUMBER_OF_NAMES; index++){
printf("%s \n",names[index]);
free(names[index]);
}
}
You can make use of 2 dimensional array. Here your variable a which is a character array stores only one character at each index.
#include <stdlib.h>
#include<stdio.h>
int main(){
int i;
char a[5];
for(i=0;i<5;i++){
printf("Enter ");
scanf("%s",&a[i]);
}
for(i=0;i<5;i++){
printf("%s \n",a[i]);
}
}
"...wrote this code to input names to array..."
char a[5] does not create 5 C strings. It is simply an array of 5 char. It provides room for only 1, 4 character C string (leaving room for the \0 terminator). If you need an array of names, of typical size the code will need an array of arrays each with space sufficient for typical names. For example:
char a[5][80] = {{0}}; //provides an array capable of containing 5 names
Also, in the read statement: scanf("%s",&a[i]);, the format code %s is expecting to process an array of char. But is provided with &a[i] which is only a single character. If you are going to use scanf, then call it like this: scanf("%s",a); Same issue with the print statement.
Make the following edits to address these basic issues:
int main(void)
{
int i = 0;
char a[5][80] = {{0}};//space for 5 names, each with up to 79 characters
//arrays are initialized to zeros
for(i=0;i<sizeof(a)/sizeof(a[0]);i++)//sizeof(a)/sizeof(a[0]) is flexible way to
//loop only through number of names.
//If array size changes, expression will still work
{
printf("Enter name %d:\n ", i+1);
scanf("%79s",a[i]);//limit input to prevent overflow
// ^^
}
for(i=0;i<sizeof(a[0])/sizeof(a[0][0]);i++)
{
printf("%s \n",a[i]);
}
return 0;
}

Quick sort function works only if last value is the largest

I'm trying to practice using Quick Sort in C. My program is a simple array of structs that takes in command line args (name1 age 1 name2 age2...etc) and outputs said ages in descending order.
It works correctly ONLY if the last age inputted is the largest. Other than that I either get no output or Seg Fault 11. Does anyone have any ideas?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NameLen 80
void print_struct();
struct people
{
char name [NameLen + 1];
int age;
}; //defining a structure//
typedef struct people PERSON;
void quicksort(struct people list[],int,int);
int main(int argc, const char * argv[])
{
int i,j;
j = 0;
int l = ((argc/2)-1);
struct people list[l]; //maximum size of array of structs
if (argc %2 == 0) //if the number of arguments is an even number
{
printf("Invalid Arguments!\n");
printf("Usage : ./hw5 name1 age1 name2 age2 ... "); //print error message and correct program usage
exit(0);
}
printf("You have entered %d persons(s) into the program \n",(argc/2));
for (i=1; i < argc; i+=2)
{
strcpy(list[j].name, argv[i]);
list[j].age = atoi(argv[i+1]);
if(list[j].age == 0)
{
printf("...Invalid age <=0. Try again.\n");
exit(0);
}
j++;
}
printf("Unsorted Names: \n");
print_struct(&list,argc);
printf ("Sorted by Age: \n");
quicksort(list,0 ,j);
for(i=0;i<j;i++){
printf("Name : %s| Age : %d\n", list[i].name, list[i].age);}//possible error here?
//Quicksort Function
Perhaps the problem is the value of j. Is j the length of list? Or the length of list - 1?
It seems like this would be what you would want:
j = length of list
printf ("Sorted by Age: \n");
quicksort(list,0 ,j-1);
for(i=0;i<j;i++){
printf("Name : %s| Age : %d\n", list[i].name, list[i].age);}
The quicksort function is fine. The issue is that you're calling it wrong:
quicksort(list,0 ,j);
The values you're passing in for first and last represent the index of the first and last elements. As evident from how you use j to loop through the elements, j is the number of elements. That means that the last element has index j-1.
So you're passing a value for last that is one element past the end of the array. When you then try to read/write this bogus element, you invoke undefined behavior which in your case (fortunately) leads to a segfault.
Pass in the actual index of the last element (i.e. one less than the size) and it runs successfully.
quicksort(list,0 ,j - 1);
Your loops are incorrect:
while(list[i].age<=list[pivot].age&&i<last)
i++;
It is possible for this loop to end with i == last, which is bad because you attempt to swap the value, which would be out of scope of the array.
while(list[j].age>list[pivot].age)
j--;
Here, since j starts as last, you start right off with reading outside of the array.
One possible remedy is to move j backwards first, then test (do-while style). Then, increment i, testing against the decremented j.
do --j; while(list[j].age>list[pivot].age);
do ++i; while(list[i].age<=list[pivot].age&&i<j);
I made the code a little bit simple (changed the array of chars to just a char to make it more simple as possible).
My thoughts are that when you call:
quicksort(list,0 ,j);
What you should call is:
quicksort(list,0 ,j-1);
Because the last parameter must be the array lenght minus 1, the last position.
I got no seg fault, when running your code, or the one I modified, if it is possible, double check the strings you are using as input.
Here is "my" vesion of the code.
Hope it helps.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NameLen 80
void print_struct();
struct people
{
char name;
int age;
}; //defining a structure//
typedef struct people PERSON;
void quicksort(struct people list[],int,int);
int main(int argc, const char * argv[])
{
int i,j;
j = 10;
struct people list[10]; //maximum size of array of structs
for (i=0; i < 10; i++)
{
list[i].name = 'a';
list[i].age = 10-i;
}
printf("Unsorted Names: \n");
for(i=0;i<j;i++){
printf("Name : %c| Age : %d\n", list[i].name, list[i].age);}//possible error here?
printf ("Sorted by Age: \n");
quicksort(list,0 ,j-1);
for(i=0;i<j;i++){
printf("Name : %c| Age : %d\n", list[i].name, list[i].age);}//possible error here?
}
void quicksort(struct people list[],int first,int last)
{
struct people temp;
int i,j,pivot;
if(first<last){
pivot=first;
i=first;
j=last;
while(i<j)
{
while(list[i].age<=list[pivot].age&&i<last)
i++;
while(list[j].age>list[pivot].age)
j--;
if(i<j){
temp=list[i];
list[i]=list[j];
list[j]=temp;
}
}
temp=list[pivot];
list[pivot]=list[j];
list[j]=temp;
quicksort(list,first,j-1);
quicksort(list,j+1,last);
}
}
after applying all the comments, this is the resulting code, which cleanly compiles, but will not link due to the two missing functions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_LEN (80)
struct people
{
char name [NAME_LEN + 1];
int age;
}; //defining a structure//
typedef struct people PERSON;
// print_struct( ptrToList, numElements )
void print_struct( PERSON *, int );
// quicksort( ptrToList, firstOffset, numElements )
void quicksort(struct people list[],int,int);
int main(int argc, const char * argv[])
{
//int i,j;
//j = 0;
//int l = ((argc/2)-1);
int l = argc/2;
struct people list[l]; //maximum size of array of structs
if (argc %2 == 0) //if the number of arguments is an even number
{
//printf("Invalid Arguments!\n");
fprintf( stderr, "Invalid Arguments!\n" );
//printf("Usage : ./hw5 name1 age1 name2 age2 ... "); //print error message and correct program usage
fprintf( stderr, "Usage : %s name1 age1 name2 age2 ... ", argv[0]);
// exit(0);
exit( EXIT_FAILURE );
}
//printf("You have entered %d persons(s) into the program \n",(argc/2));
printf("You have entered %d persons(s) into the program \n", l);
//for (int i=1; i < argc; i+=2)
for (int i=1, j=0; j < l; i+=2, j++)
{
//strcpy(list[j].name, argv[i]);
memset( list[i].name, '\0', NAME_LEN+1);
strncpy( list[j].name, argv[i], NAME_LEN );
list[j].age = atoi(argv[i+1]);
if(list[j].age == 0)
{
fprintf( stderr, "...Invalid age <=0. Try again.\n");
//exit(0);
exit( EXIT_FAILURE );
}
//j++;
}
printf("Unsorted Names: \n");
//print_struct(&list,argc);
print_struct( list, l );
//printf ("Sorted by Age: \n");
//quicksort(list,0 ,j);
quicksort( list, 0, l );
printf ("Sorted by Age: \n");
// //for(i=0;i<j;i++)
//for( int i=0; i<l; i++ )
//{
// printf("Name : %s| Age : %d\n", list[i].name, list[i].age);
//}//possible error here?
//}
print_struct( list, l);
} // end function: main
//Quicksort Function

Malloc for structures

I am not getting the correct output here,
The code takes the no of inputs and option as an input, then takes the name of student year and gender and based on option provided gives the output. The output can be the name appearing first in the dictionary or the smaller value of the year amongst the inputs.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student_record
{
int passing_year;
char gender;
char name[20];
};
typedef struct student_record student;
student* find_specific(student* find, int option_num, int number)
{
int i;
student* temp = find;
int opt = option_num;
int num = number;
if(opt==1)
{
for(i=0; i<num; i++)
{
if( strcmp(temp->name, find[i].name) >0)
temp = find+i;
}
}
else
{
for(i=0; i<num; i++)
{
if (temp->passing_year > find[i].passing_year)
temp = find+i;
}
}
return temp;
}
int main() {
student* example;
student* final;
int i;
int option_num, number_of_students;
printf("Enter 2the number of students, option number");
scanf("%d" "%d", &number_of_students, &option_num);
example = (student* )malloc(number_of_students * sizeof(student));
printf("Enter the name, passing year and gender");
for(i=0; i< number_of_students; i++)
{
scanf("%s" "%d" "%c", example[i].name, &example[i].passing_year, &example[i].gender);
}
final = find_specific(example, option_num, number_of_students);
printf("%s" "%d" "%c", final->name, final->passing_year, final->gender );
return 0;
}
i am getting a segmentation fault. I can't figure out exactly where am I screwing up.
Your scanf() and printf() format strings are probably wrong.
scanf("%s" "%d" "%c", example[i].name, &example[i].passing_year, &example[i].gender);
should probably be
scanf("%s %d %c", example[i].name, &example[i].passing_year, &example[i].gender);
(without the extra quotes). The compiler will concatenate adjacent
string literals, so instead of a compiler error, it interpreted your format string as equivalent to "%s%d%c" (without whitespace in between).
That probably doesn't match the layout of your input, so some of the values were probably left uninitialized in a way that caused problems later.
You should always check the return value of scanf and similar library functions,
to ensure that you got the input format you told the compiler to expect.

Expression must have class type error

I'm working on a homework assignment and I've hit a brick wall. I think I have all of the code that I need, I just need to get the program to compile. The object of the assignment is
Create a structure to hold student names and averages. The structure should contain a first name, last name and an integer grade average.
Then:
Write a program that will do the following:
1.) Create an array of pointers to these student structures.
2.) Prompt the user for names and averages.
3.) After you get the student’s information use malloc to provide the memory to store the information.
4.) Place the address of the student, returned by malloc, into the pointer array.
5.) AFTER the user indicates there are no more students:
Search the data entered and find the highest and lowest grade
average.
a)Print the name and grade for the highest grade
b)Print the name and grade for the lowest grade
c)Print the average of all grades entered
Here is my code:
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#define SIZE 25
int enterStudents (int ePointArray[SIZE]);
void searchData (int *sPointArray, int *sHigh, int *sLow);
int calculateAvg (int, int *avgPointArray);
void printData (int, int *pHigh, int *pLow);
struct student
{
char firstName[20];
char lastName[20];
int average;
};
int main()
{
int pointArray[SIZE], high[3], low[3];
int i = 0, studentCounter, avgGrade;
for (i = 0; i < SIZE; i++)
pointArray[i] = 0;
studentCounter = enterStudents(pointArray);
searchData(pointArray, high, low);
avgGrade = calculateAvg(studentCounter, pointArray);
printData(avgGrade, high, low);
return 0;
}
int enterStudents (int ePointArray[SIZE])
{
char tempFname[20], tempLname[20], yesNo[2] = "y";
int tempAvg, counter = 0;
int *studPtr;
struct student aStud={"\0", "\0", 0};
while( counter < SIZE && strcmp(yesNo, "y")==0)
{
printf(" Enter first name: ");
scanf("%s", tempFname);
printf(" Enter last name: ");
scanf("%s", tempLname);
printf(" Enter grade average:");
scanf("%d", tempAvg);
strcpy(aStud.firstName, tempFname);
strcpy(aStud.lastName, tempLname);
aStud.average = tempAvg;
studPtr = malloc(sizeof(struct student));
ePointArray[counter] = *studPtr;
counter++;
printf("/n");
printf(" Do you have more students? yes or no:");
scanf("%s", yesNo);
}
return counter;
}
void searchData (int sPointArray[SIZE], int sHigh[3], int sLow[3])
{
int searchCounter = 0;
while( searchCounter = 0)
{
if( *sPointArray[searchCounter].average > *sPointArray[searchCounter+1].average)
{
sHigh[0] = &sPointArray[searchCounter].firstName;
sHigh[1] = &sPointArray[searchCounter].lastName;
sHigh[2] = &sPointArray[searchCounter].average;
}
if( *sPointArray[searchCounter].average < *sPointArray[searchCounter+1].average)
{
sLow[0] = &sPointArray[searchCounter].firstName;
sLow[1] = &sPointArray[searchCounter].lastName;
sLow[3] = &sPointArray[searchCounter].average;
}
searchCounter++;
}
}
int calculateAvg( int totalStudents, int avgPointArray[SIZE])
{
int sum = 0;
int avgCounter;
double overallAvg;
for( avgCounter = 0; avgCounter < totalStudents; avgCounter++)
sum = sum + *avgPointArray[avgCounter].average;
overallAvg = sum/totalStudents;
return overallAvg;
}
void printData (int pAverage, int pHigh[3], int pLow[3])
{
printf(" Highest Grade: %s %s %d", pHigh[0], pHigh[1], pHigh[3]);
printf("/n");
printf(" Lowest Grade: %s %s %d", pLow[0], pLow[2], pLow[3]);
printf("/n");
printf(" Average Grade: %d",pAverage);
}
The main chunk of problems come from the searchData function. In the if statements, every occurrence of *sPointArray and &sPointArray is underlined in red and the error reads
"Error: expression must have class type"
The same thing also happens in the calculateAvg function with *avgPointArray in the for loop. I know that the error is a fairly common problem for noobie C programmers (i.e myself) and that it generally has to do with writing the code as a function instead of a statement or something like that, but I can't for the life of me find where I have went wrong. Any help would be highly appreciated. I've been working at this for so long my vision is blurring.
Also, for anyone who solves this in like two seconds and wants proof that I'm a true idiot, there is an error in the enterStudents function where it says StudPtr = malloc(sizeof...). The error shows under the assignment symbol and says
"Error: a value of type "void*" cannot be assigned to an entity of type "int*".
I understand this concept in theory, but some advice for how to fix it would be highly appreciated.
Thank you in advance for any help.
You declare the sPointArray as an array of integers, but use it as an array of structures.

warning: format %s expects type char * but argument 2 has type int

I have already looked at other related questions, and none of them helped this case.
I am getting the warning listed in the title of my question, and my code for main is as follows:
int main( int argc, char *argv[] ) {
char *rows;
int i, n;
printf("\nEnter the amount of rows in the telephone pad: ");
scanf("%d", &n);
rows = (char *) malloc( sizeof( char ) * n );
printf("\nNow enter the configuration for the pad:\n");
for( i = 0; i < n; i++ ) {
scanf("%s", &rows[i]);
printf("\n\t%s\n", rows[i]);
}
return 0;
}
The user is to enter a number (say, 4), which will be scanned into n. The space is malloc'ed for the rows of the telephone pad. The user then will enter the n amount of rows for the configuration of the telephone pad. An example would be:
123
456
789
.0.
So I am confused as to why my last printf statement is getting this error.
Note: I also tried scanf("%s", rows[i]);: still got the error.
Note 2: I tried running the program anyways. Got a segmentation fault.
Note 3: I have #include <stdio.h> and #include <stdlib.h> at the top of my .c program.
Note 4: I have gcc'ed the program as such: gcc -ansi -pedantic -Wall tele.c.
Thank you for the help.
rows[i] isn't a char* -- it's not a "string".
(And you can't fit 3 characters (plus null terminator) in one character.)
As others have pointed out, you are allocating space for n chars, but you really want space for n rows with 4 chars each (3 characters entered by the user, and a null terminator).
There's a couple of ways to do this. You can first allocate n char * variables to point to the rows, then allocate 4 bytes for each row:
int main( int argc, char *argv[] )
{
char **rows;
int i, n;
printf("\nEnter the amount of rows in the telephone pad: ");
scanf("%d", &n);
rows = malloc( n * sizeof rows[0] );
printf("\nNow enter the configuration for the pad:\n");
for( i = 0; i < n; i++ ) {
rows[i] = malloc(4);
scanf("%3s", rows[i]);
printf("\n\t%s\n", rows[i]);
}
return 0;
}
Or, you can allocate n 4-character arrays up front:
int main( int argc, char *argv[] )
{
char (*rows)[4];
int i, n;
printf("\nEnter the amount of rows in the telephone pad: ");
scanf("%d", &n);
rows = malloc( n * sizeof rows[0] );
printf("\nNow enter the configuration for the pad:\n");
for( i = 0; i < n; i++ ) {
scanf("%3s", rows[i]);
printf("\n\t%s\n", rows[i]);
}
return 0;
}
your printf is passing in a char, not a %s
you are saying get the i'th char in the string 'rows'.
More importantly, your whole technique is going to fail badly....
I think you want an array of strings.... or you want to change your scanf to a %c

Resources