Program crashes when trying to scan strings into array - c

I am writing a program to intake exactly 5 peoples last names and their votes. Which will display the names of the people entered, the corresponding votes, and also the winner.
I need the names of the people into one array of strings. That is where the program crashes. Not sure if I can modify this to make it work or if I need to redo it.
the malloc function seems to be a recurring fix for this type of problem ?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int TotalVotes(int voteArray[],int size)
{
int Sum=0;
for (int i=0;i<size;i++)
{
Sum+=voteArray[i];
}
return Sum;
}
int Winner(int voteArray[],int size)
{
int max;
max=0;
if (voteArray[1]>voteArray[max])
max=1;
if (voteArray[2]>voteArray[max])
max=2;
if (voteArray[3]>voteArray[max])
max=3;
if (voteArray[4]>voteArray[max])
max=4;
return max;
}
void main()
{
char nameArray[5];
int voteArray[5],Total,winner;
for (int i=0;i<5;i++)
{
voteArray[i]=0;
}
for (int j=0;j<5;j++)
{
printf("Enter the name of the candidate number %d\n",j+1);
scanf("%s",nameArray[j]);
printf("Enter that persons number of votes\n");
scanf("%d",&voteArray[j]);
}
Total=TotalVotes(voteArray,5);
winner=Winner(voteArray,5);
printf("%s\t%s\t%s\n","Candidate","Votes Received","% of Total Votes");
for (int y=0;y<5;y++)
{
printf("%s\t%d\t%0.2f\n",nameArray[y],voteArray[y],(float)voteArray[y]/Total);
}
printf("The Winner of The Election is %s\n",nameArray[winner]);
}

char nameArray[5]; is should be like char nameArray[5][20];

Yeah, in C, strings are represented by character arrays (char* or char[]).
Also, you should get fgets instead of scanf with strings for two reasons:
Fgets helps prevent buffer overflow because it knows the size of the string in advance.
Fgets will always run because it does not leave characters in the input buffer like scanf does.
The prototype for fgets looks somewhat like this (you can use stdin for the FILE pointer to read in from the keyboard, but realize that fgets keeps newlines):
fgets( char *output_variable, unsigned int string_length, FILE *input_file );
Also, if you use scanf, you should do a lot more error checking for invalid input.

Related

Segmentation error while working with strings

Given a string, num, consisting of alphabets and digits, find the frequency of each digit(0-9) in the given string.
'''
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include<ctype.h>
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
char num[20];
int i;
int count[15]={0};
scanf("%s",num);
for(i=0;i<10;i++){
printf("\n");
for(int j=0;j<strlen(num);j++){
if(isdigit(num[j])){
if(i == num[j]-'0'){
count[i]+=1;
}
}
}
printf("\nCount %d:%d",i,count[i]);
}
for(i=0;i<10;i++){
printf("%d ",count[i]);
}
return 0;
}
'''
OUTPUT:
Count 0:5
Count 1:9
Count 2:5
Count 3:12
Count 4:8
Count 5:11
Count 6:15
Count 7:4
Count 8:4
exited, segmentation fault
Why is it not working when checking if the digit is 9?
When looking at your output, it seems that you have entered a string much longer than 19 characters. So your program has undefined behavior.
This
scanf("%s",num);
is something that you should never do. Remember to limit the input to the size of your buffer. That is:
char num[20]; // Size of buffer is 20
scanf("%19s",num);
^^
At max allow 19 characters so that there is also room for the string termination
Or - perhaps better - use fgets instead of scanf. One benefit of fgets is that it takes the buffer size as argument - consequently you never forget to specify it.
Also notice that your outer for loop is unnecessary. You can update the array directly using a single loop.
// for(i=0;i<10;i++){ Delete this - it's not needed
for(int j=0;j<strlen(num);j++)
{
if(isdigit(num[j]))
{
count[num[j]-'0']+=1; // Update array
}
}
BTW: You only need 10 elements in the counter, i.e.
int count[15]={0}; ---> int count[10]={0};

Not able to take string and float as input in a single line in C

What I have till now is this. I am not able to figure out how to take the input as mentioned and solve this problem?
#include<stdio.h>
#include <stdlib.h>
#include<float.h>
int main()
{
char s[50];
float mil,min=FLT_MAX;
while(scanf("%s#%f",s,&mil)!=-1)
{
printf("%s\n",s);
if(mil<min)
min=mil;
}
}
EDIT: My problem is that when I print the string s inside the loop, "Zantro#16.15" is printed whereas I want only "Zantro" to be stored in s and 16.15 to be stored in mil
%s scans up until a whitespace. Scan up until a # instead.
while (scanf("%[^#]#%f", s, &mil) == 2)
Remember to specify the maximum buffer size in the scanning format to protect against overflows:
while (scanf("%49[^#]#%f", s, &mil) == 2)
Well the scanf function can not easily determine, that you want the # sign to be a delimiter. Therefore you need to add an extra step to split up the strings into proper parts and store them for later comparison.
Have a look at strtok function in c.
http://www.c-howto.de/tutorial/strings-zeichenketten/string-funktionen/string-zerteilen/
Here is a solution that prints the requested string:
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <string.h>
int main()
{
char s[50];
char mins[50];
float mil,min=FLT_MAX;
int rc;
int done=0;
while (done == 0)
{
rc = scanf("%49[^#]#%f", s, &mil);
if (rc != 2)
{
done = 1;
continue;
}
if (mil < min)
{
min = mil;
strcpy(mins, s);
}
}
printf("%s\n", mins);
return 0;
}
Execution:
./sc
Zantro#16.15
Zirty#12.5
Gamry#9.8
Gamry
#include<stdio.h>
#include <stdlib.h>
#include<float.h>
int main()
{
char s[50];
float mil, min = FLT_MAX;
while (scanf("%[^#]#%f", s, &mil) == 2)
{
printf("%s\n", s);
if (mil < min)
min = mil;
}
}
Input:Zantro#16.15Zity#12.5Gamry#9.8
OutPut:
Zantro
Zity
Gamry
If you want to split your input in the scanf to string and float, you have to write those two types separately. For example, ("%s %f"). This string tells the function, what will be the arguments types. Therefore, if you write it like this ("%s#%f") the scanf function has a problem to understand, what will be the inputs types. In addition, if you write ("%s #%f") it will get two inputs like this " #". Your problem here is the space between the two arguments. Because, I didnt find how to get the input without this space. I'm recommending you to try splitting the input in another way.
For example, take one string that holds the intaier input to string buffer-> scanf("%s",sBuffer).
and split that to different variables after that.

Getting an infinite running program when using scanf

I'm getting an infinite running programm when I use the following code to read a string from keyboard and save it within a structured vector.
scanf("%s", strk_zgr_fp->bezeichnung, (int)sizeof(strk_zgr_fp->bezeichnung - 1));
Simply nothing happens after this line is reached and the program runs infinitly.
I know scanf() isn't recommended. We're using it only within our C beginners course and I want you to keep it in mind, ie please don't recommend other function rather than above mentioned for the moment.
Any help is much appreciated, thanks in advance.
#include <stdio.h>
typedef struct {
int nummer;
char bezeichnung;
int menge;
float preis;
} artikel;
void eingabe_artikel(artikel *strk_zgr_fp, int i_fp);
void ausgabe_artikel(artikel *strk_zgr_fp, int i_fp);
void main(void) {
artikel artikelliste[10];
artikel *strk_zgr;
int anzahl;
do {
printf("Bitte eine #Artikel eingeben [<= 10]: ");
scanf("%d", &anzahl);
if(anzahl < 1 || 10 < anzahl)
printf("\nEs wurde eine falsche #Artikel eingegeben.");
} while(anzahl < 1 || 10 < anzahl);
for(int i = 0; i < anzahl; i++)
eingabe_artikel(&artikelliste[i], i);
int i;
for(strk_zgr = artikelliste, i = 0; strk_zgr < artikelliste + anzahl;
strk_zgr++, i++)
ausgabe_artikel(strk_zgr, i);
}
void eingabe_artikel(artikel *strk_zgr_fp, int i_fp) {
printf("\nBitte den %d. Artikel eingeben: ", ++i_fp);
printf("\nNummer: ");
scanf("%d", &strk_zgr_fp->nummer);
printf("Bezeichnung: );
scanf("%s", strk_zgr_fp, (int)sizeof(strk_zgr_fp->bezeichnung - 1)); /* <-- */
printf("Menge: ");
scanf("%d", &strk_zgr_fp->menge);
float preis;
printf("Preis: );
scanf("%f", &preis);
strk_zgr_fp->preis = preis;
}
void ausgabe_artikel(artikel *strk_zgr_fp, int i_fp) {
printf("\n%d. Artikel: ", ++i_fp);
printf("\nNummer:\t%d", strk_zgr_fp->nummer);
printf("\nBezeichnung:\t%s", strk_zgr_fp->bezeichnung);
printf("\nMenge:\t%d", strk_zgr_fp->menge);
printf("\nPreis:\t%.2f EUR\n", strk_zgr_fp->preis);
}
NetBeans Version
Complier Version
Many problems in the code. Please at least fix the missing ending quotes on the printf() calls.
Now to the beef:
1) Your structure is wrong. 'Bezeichnung' is defined as a single character, not a string.
typedef struct {
int nummer;
char bezeichnung[100];
int menge;
float preis;
} artikel;
2) You cannot use scanf() in the way you did. If you want to limit the input length (which always is a good idea), you need to pass the maximum length into the format string.
Do you nee to use scanf()?? Because it gets messy from here on....
As your maximum input length might be variable or subject to change (see 1.), you need to build the format string for scanf. Something like this:
char format_str[15];
format_str[0] = '%';
//Dont use itoa(), it is not C standard.
sprintf(&format_str[1], "%d", (int)sizeof(strk_zgr_fp->bezeichnung) - 1);
strcat(format_str, "s");
scanf(format_str, strk_zgr_fp->bezeichnung);
Hope that gets you going.
PS: You need to include string.h for strcat().
I tried it out and it worked fine for me. Not sure on this sprintf() function. Could you please explain why I'm supposed to use it? By now, I used this code: char format_str[20]; format_str[0] = '%'; strcat(format_str, "s"); printf("Bezeichnung: "); scanf(format_str, strk_zgr_fp->bezeichnung);
While that works, you are missing out on limiting the length of the user's input. That is why I proposed using sprintf() to create a (sub)string containing the maximal allowable length of the user input, depending on how large your 'bezeichnung' is defined in the struct. Suppose 'bezeichnung' has a limit of 100 characters, you would want to limit the input to 99 (+1 for the zero-termination), so you want a scanf format string like this: "%99s".
chux has provided a much more compact version of my three lines, but I think, in the beginning, you will have it easier to just assemble such format strings piece by piece, at the same time learning how to a) change individual characters in a string, how to use sprintf() in a basic way, and how to concatenate strings with strcat().
There was another example which I did and the course leader provided a scanf() function like this to read a string: scanf("%s", &(strk_zgr_fp->bezeichnung));. I thought when I'm reading a string the address operator isn't used. The only difference is the address operator now is used and the element was put into brackets.
Now, I think this is bad practice. It works, but is superfluous. Consider this small code snippet:
#include <stdio.h>
#include <stdlib.h>
struct test{
int i;
char a_str[10];
};
int main()
{
struct test a_test;
printf("Normal array adress taking: %p\n", a_test.a_str);
printf("Using '&' to take adress of array: %p\n", &(a_test.a_str));
return 0;
}
Hope that helps.

Program crashes after perfoming strcpy() function

I need some help with an assignement I have to do for school which consists in sorting some books after the title,author and the publication date of it. All the infos are given as a string in a txt file using a delimiter between them. The problem is that I don't manage to properly read the data, my program crashes after I try to perform a strcpy(). Can you guys help me with this and tell me what have I done wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book
{
char author[100],title[100];
int year;
};
int main()
{
struct book b[25];
int i,n;
char intro[25][150],*p;
const char delim[2] = "#";
FILE *fp;
fp=fopen("text.txt", "r");
fscanf(fp,"%d",&n);
for(i=0;i<=n;i++)
{
fgets(intro[i], sizeof (intro[i]), fp);
p=strtok(intro[i], delim);
strcpy(b[i].title,p);
p=strtok(NULL, delim);
strcpy(b[i].author,p); /// The program works until it reaches this point - after performing this strcpy() it crashes
if(p!=NULL)
{
p=strtok(NULL,delim);
b[i].year=atoi(p);
}
}
return 0;
}
An example of input could be this:
5
Lord Of The Rings#JRR Tolkien#2003
Emotional Intelligence#Daniel Goleman#1977
Harry Potter#JK Rowling#1997
The Foundation#Isaac Asimov#1952
Dune#Frank Herbert#1965
The problem is with the newline left in the file after the initial fscanf() call.
This
fscanf(fp,"%d",&n);
reads the 5 and the subsequent fgets() reads just the \n. So this is not what you want. Read n using fgets() and convert it into integer using sscanf() or strto*. For example, instead of the fscanf() call, you can do:
char str[256];
fgets(str, sizeof str, fp);
sscanf(str, "%d", &n);
to read the n from file.
You should also check if strtok() returns NULL. If you did, you would have figured out the issue easily.
Also, your need to go from 0 to n-1. So the condition in the for loop is wrong. It should be
for(i=0; i<n; i++)

Array of "strings" in C

I know that there is a question with the same name, but it didn't work for me.
I'm making a home-compiler, returns the words that belongs to a language.
The words to analyze are in this vector:
char *cadenas[]= {"123", "4567L", "5a23", '\0'};
Now I want to enter the words by console, but strings can't be used in C, how can I do it? (Without making a matrix possibly)
void getCadenas(char *cadenas[]){
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
char cadena[15];
gets(cadena);
int x=0;
while(cadena[0]!='z'){
strcpy(cadenas[x],cadena);
x++;
gets(cadena);
}
}
If I understand your problem correctly, you would like the user to be able to enter multiple strings, until he/she types z
See if this piece of code helps you out. The strings will be stored in the cadenas array, as requested.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define MAX_CADENAS 100
#define MAX_CADENA_LEN 255
int getCadenas(char **cadenas){
int x=0;
char cad[MAX_CADENA_LEN+1];
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
while(x<MAX_CADENAS) {
scanf("%s", cad);
if (strcmp(cad,"z")==0)
break;
cadenas[x] = malloc(strlen(cad)+1);
strcpy(cadenas[x], cad);
x++;
}
return x;
}
char *cadenas[MAX_CADENAS];
int main() {
int num, i;
num = getCadenas(cadenas);
for (i=0;i<num; i++) {
printf("%s\n", cadenas[i]);
}
}
Note0: the code assumes you know in advance what the maximum number of input strings can be (100). It also assumes a maximum size for each input string (255 characters)
Note1: gets is deprecated. Also, instead of scanf, you might want to use fgets.
Note2: the present code is for illustrative purpose only. It allocates memory for each input string, but it assumes no error occurs in doing so (i.e. it does not check what malloc returns).
Note3: the allocated memory blocks must be freed when not used anymore (hint: cycle through the cadenas array and use free)
Assuming you don't mind carrying on with fixed-size strings and arrays, here is your original program modified:
#include <stdio.h>
#include <string.h>
#define MAX_CADENAS 100
#define CADENA_LIMIT 1000
// ...
void getCadenas(char cadenas[MAX_CADENAS][CADENA_LIMIT]){
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
int x;
for(x=0; x<MAX_CADENAS-1; x++){
char cadena[CADENA_LIMIT];
fgets(cadena, CADENA_LIMIT, stdin);
// fgets will copy the newline character, we don't want that
int cadenaLength=strlen(cadena);
if(cadena[cadenaLength-1]=='\n')
cadena[cadenaLength-1]='\0';
if(strcmp(cadena, "z")==0) break;
strcpy(cadenas[x], cadena);
}
cadenas[x][0]='\0';
}
// ...
Prefer fgets as you can prevent overflow of the fixed-size strings. Unfortunately it copies the newline as well, so I have code to handle that. The result is an array in the form you originally specified (except it ends with "" which we decided was what you were after in the comments).
You can read arbitrary sized strings in C like in other languages, but you would need to implement it with malloc() and co. Allocating dynamically sized memory is primarily controlled with the functions malloc, calloc, realloc and free. This would make the program unavoidably more complicated. Here is one way of doing this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ...
char *getCadena(){
int length=0, capacity=1, character;
char *cadena=malloc(1); // sizeof(char) is always 1
while((character=getchar())!=EOF){
if(character=='\n') break;
// Add character to string
length++;
if(capacity<length){
capacity*=2;
cadena=realloc(cadena,capacity);
}
cadena[length-1]=character;
}
// Add terminator to cadena
length++;
if(capacity<length){
capacity*=2;
cadena=realloc(cadena,capacity);
}
cadena[length-1]='\0';
return cadena;
}
char **getCadenas(){
printf("Enter cadenas to be analyzed ('z' to scape) \n \n");
int length=0, capacity=1;
char **cadenas=malloc(sizeof(char *));
for(;;){
char *cadena=getCadena();
if(strcmp(cadena,"z")==0){
free(cadena);
break;
}
// Add pointer to cadenas array
length++;
if(capacity<length){
capacity*=2;
cadenas=realloc(cadenas,capacity*sizeof(char *));
}
cadenas[length-1]=cadena;
}
// Add NULL to end of cadenas
length++;
if(capacity<length){
capacity*=2;
cadenas=realloc(cadenas,capacity*sizeof(char *));
}
cadenas[length-1]=NULL;
return cadenas;
}
void freeCadenas(char **cadenas){
int i=0;
while(cadenas[i]!=NULL){
free(cadenas[i]);
i++;
}
free(cadenas);
}
// ...
This works mostly the same as the previous function, except you should use freeCadenas eventually, and I end the array with NULL instead of "" which is customary.
The code is a lot longer, but it's pretty typical of more sophisticated C code with less arbitrary limits. In fact real C code usually has more robust handling of errors and more generic functions for managing dynamic arrays. If you actually manage to make this "home-compiler", however, you will figure all this out for yourself.

Resources