Why am I not able to enter desired number of inputs? - c

The problem is about taking input of strings x number of times using an array of pointers. x is the value entered by the user. I wrote the following code for the same. But the program is taking only x-1 inputs.
I have inserted fflush(stdin) because I think the scanf is consuming an enter first but I don't know from where.
I have tried using gets but with no use.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
//code to take input in an array of pointers
int x,i,j,length;
char ch[50],*t;
printf("How many names you want to sort:\n");
scanf("%d",&x);
char *names[x];
char *p;
printf("Enter the names:\n");
for(i=0;i<x;i++)
{
fflush(stdin);
scanf("%[^\n]s",ch);
length = strlen(ch);
p = (char *)malloc((length+1) * sizeof(char));
strcpy(p,ch);
names[i] = p;
}
return 0;
}

Why bother with complex format strings if you don't have to? Use fgets.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void err(const char * msg) {
fprintf(stderr, msg);
exit(1);
}
int main()
{
int x,i;
char ch[50];
printf("How many names you want to sort:\n");
if(!fgets(ch, 50, stdin)) err("Error reading line");
if(sscanf(ch, "%d",&x) != 1) err("Could not read integer");
// Better than using VLA
char **names = malloc(x*sizeof(*names));
if(!names) err("Error allocating names");
printf("Enter the names:\n");
for(i=0;i<x;i++) {
if(!fgets(ch, 50, stdin)) err("Error reading line");
ch[strcspn(ch, "\n")] = 0; // Remove newline
if(!(names[i] = strdup(ch))) err("Error duplicating string");
}
for(int i=0; i<x; i++)
printf("name %d: %s\n", i, names[i]);
}
Whenever a function has a return value that may indicate an error you should ALWAYS check it, and here that is the case for malloc, fgets, strdup and sscanf and. Read the documentation to find out what it actually returns to see how to check for errors. sscanf returns the number of successful assignments, and the other three returns a pointer which is NULL on failure.
You wrote in the comments that you are learning from the book "Let us C". A better fitting title would be "How to not code C". I've had a quick look at it and, it is really really bad. Apart from teaching very outdated C, it also teaches very bad habits in general, and many of the things you can read is completely WRONG. Actually, the majority of questions about C can be traced to that book, or at least could have. Two prime examples is that it consistently avoids very important stuff, such as error checking functions like scanf and malloc. I have not read every line, but I think it does not even mention how to error check scanf even once. It also uses the function gets which is not only deprecated but completely removed from newer C standards because it is so dangerous. It also says that you can modify a string literal, which is undefined behavior in C.

Related

How to scan input from terminal and add to array?

as a homework assignment for my computing 1 college course, my professor has given me the task of having the user input a string of characters into the terminal, taking that string, adding it into an array, then printing the array and printing the array backwards. I think that I know of a way to print the array backwards, however, I cannot come up with a way to read from the terminal and add the characters from the terminal to an array. I have tried doing the following:
char ch;
for (int i = 0; i <= 80 || str[i] == '\n'; ++i) {
scanf_s("%c", &str[i]);
}
I am wondering if someone could explain to me why this section of code does not operate as expected, and if someone could give me some other ideas to try. Thank you.
You are using scanf_s with %c specifier incorrectly.
Please take notice of compiler warnings, there is a size argument missing.
Microsoft's scanf_s is not a direct replacement for scanf.
Unlike scanf ... scanf_s ... requires the buffer size to be specified for all input parameters of type c, C, s, S, or string control sets that are enclosed in []. The buffer size in characters is passed as an additional parameter immediately following the pointer to the buffer or variable.
scanf_s("%c", &str[i], 1);
You might also want to filter out any newline which may have been left in the buffer, with
scanf_s(" %c", &str[i], 1);
notice the added space.
Why your code is showing this type of behaviour...
use scanf instead of scanf_s
the conditions you have provided in the for loop are wrong
#include <stdio.h>
int main()
{
char ch;
char str[1000];
int i;
for (i = 0; i <= 80 ; i++)
{
scanf("%c", &str[i]);
if(str[i]=='\n')
{
str[i]='\0';
break;
}
}
printf(str);
}
I could show you the same task in simple manner. I have tried to answer your question in your way. That's why it may seem complicated.
#include <stdio.h>
#define MAX 25
int main()
{
char buf[MAX];
fgets(buf, MAX, stdin);
printf("%s\n", buf);
return 0;
}
fgets- Reads until new line character encountered or maximum limit of character array.

Bus error (core dumped) error (ubuntu) C program

I have a program in which a user inputs how many sentences they want, and then then be prompted to input the sentences. they cannot enter more than ten sentences. when i test, if i enter more than 5, i get a bus error code. here is my code, i am calling two functions in .h files that i dont believe are relevant but i will provide them anyways.
//this program will take in user input for a number of sentences up to ten, each with 100 char or less, and convert them all to uppercase
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "convert.h"
int main () {
int i; //increment
int numberofsentences; //number of sentences
char **sentence_array; // sentence array
sentence_array = (char **)malloc(numberofsentences*sizeof(char));
printf ("I will take up to ten sentences of up to 100 chars each, and convert them to uppercase, as well as give you stats on them. \n");
printf ("How many sentences would you like? \n");
scanf ("%d", &numberofsentences);
fgetc(stdin);
//user inputs the sentences based on the number that was provided
for (i = 0; i< numberofsentences; i++) {
sentence_array[i] = (char *)malloc(100 * sizeof(char));
printf ("Enter sentence :");
fgets(sentence_array[i], 101, stdin);
printf ("\n");
}
//call function that converts all arrays to uppercase
convertAll(sentence_array, numberofsentences);
printf("Your converted sentences are: \n");
//print out every sentence thats converted to uppercase
for (i = 0; i < numberofsentences; i++){
//convertSentence(sentence_array[i]);
printf("%s", sentence_array[i]);
}
}
and functions.c file
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "convert.h"
//function to convert char array to uppercase
void convertSentence(char *sentence){
int i;
for (i = 0; i <strlen(sentence); i++){
sentence[i] = toupper(sentence[i]);
}
}
//function to convert array of all sentences and converts all to upper
void convertAll(char **sentenceList, int numOfSentences){
int i;
for (i = 0; i < numOfSentences; i++){
convertSentence(sentenceList[i]);
}
}
i feel like its something to do with the memory allocation.
and as a note: i know that scanf and fgets are terrible, but my professor told us to use them so ... thanks for helping
that's expected because
sentence_array = (char **)malloc(numberofsentences*sizeof(char));
doesn't allocate enough memory for numberofsentences pointers. So after a few sentences stored, you get a memory violation or any other UB.
The sizeof is wrong, it should be:
sentence_array = malloc(numberofsentences*sizeof(char *));
Aside: no need for cast: Do I cast the result of malloc? (answer is no, BTW)
EDIT: my answer is incomplete, H.S. pointed out the other part of the problem (uninitialized value), that can be easily avoided by:
enabling the warnings
reading them
(plus the other fgets boundary error)
that'll teach me to try to valgrind OP code manually.
In this statement:
sentence_array = (char **)malloc(numberofsentences*sizeof(char));
you are using the local variable numberofsentences before initializing it, which is an undefined behavior. Also, sentence_array should be allocating memory of an array of char pointers i.e. numberofsentences*sizeof(char *) and move this statement below the numberofsentences input statement.
So, it should be like this:
scanf ("%d", &numberofsentences);
fgetc(stdin);
sentence_array = malloc(numberofsentences*sizeof(char *));
[You don't need to cast the malloc result]
Also, here
fgets(sentence_array[i], 101, stdin);
^^^
the buffer overflow can occur. The sentence_array[i] has been allocated memory to hold 100 characters and you are giving 101 as the maximum number of characters to be copied to sentence_array[i]. The fgets() reads characters from stream and stores them into the buffer (here, sentence_array[i]) until (num-1) (here, 101-1) characters have been read or either a newline or the end-of-file is reached, whichever happens first and a terminating null-character is automatically appended after the characters copied to the buffer. So, it could cause the buffer overflow. It should be:
fgets(sentence_array[i], 100, stdin);

How do I get the user to input a word for string comparison?

I'm running a while loop so the user can constantly enter expressions, until they indicate they want to quit the program. I'm using strcmp() to compare two strings so as soon as they enter quit the program will stop. But the program keeps going, any Ideas?
#include <stdio.h>
#include <string.h>
int main()
{
int min12=0;
char opper;
int x=0;
int min13;
char *Repeatprog="cont";
char *Repeatprog1="quit";
while (strcmp(Repeatprog,Repeatprog1))
{
printf("enter the integer number \n");
scanf( "%d %c %d", &min12, &opper, &min13);
printf("%d %c %d\n", min12, opper, min13);
printf("Type the word quit to end program\n");
scanf("%s", Repeatprog);
}
printf("Good Bye");
return 0;
}
Remember always that an Array is a Pointer to the first object of the array.
And secondly, in your call to scanf() you only read a character. Not a whole string (represented by %s in C)
So in conclusion, your call to scanf() shouldn't have a pointer and should have a string instead of a character.
scanf("%s", Repeatprog);
or simply
gets (Repeatprog);
EDIT :
As the commenter #EOF said, gets() is not a good idea since it can lead to Undefined Behaviour. That's because the program can read more characters than it should have and lead to overflow, thus it isn't secure.
So I recommend using char *fgets(char *str, int n, FILE *stream)
Note:
Also, your code is using string literals. So if you make any attempt to change the content of the char pointer then it will lead to Undefined Behaviour.
For this note, please thank the guys below me [comments]. I made a huge mistake and I'm sorry.

'fgets' runs after 'printf'

I'm slowly learning C. I read this page about input and output dealing with strings here: http://www.cprogramming.com/tutorial/c/lesson9.html
In the last code example, fgets is used to get and assign the input to a variable to the char array name. I tried implementing something similar in my own program.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
/* This is my very first C program! */
bool test=true;
/* Function Prototypes */
int mult(int x, int y);
/* Structures */
struct Person {
int age;
char name[256];
};
/* Complicated Array ;P */
struct Person *FirstPeriod[22];
char FakeString[100];
void PracticeStrings()
{
int i;
fgets(FirstPeriod[0]->name, 256, stdin);
for (i=0;i<256;i++)
{
if (FirstPeriod[0]->name[i]=='\n')
FirstPeriod[0]->name[i]='\0';
}
printf("\n\nHello Student 0: %s",FirstPeriod[0]->name);
}
int main()
{
struct Person DadeLamkins;
DadeLamkins.age=16;
int numb;
int x;
int *numb_address=&numb;
numb_address=malloc(sizeof(*numb_address));
FirstPeriod[0]=&DadeLamkins;
if (true)
printf("-__- \n\n");
printf("Please enter a number: ");
scanf("%d", &numb);
switch (numb) {
case 0:
printf("Dude, 0 is lame...\n");
break;
case 7:
printf("Dude, 7 is my favorite number!\n");
break;
default:
printf("You entered %d\n", numb);
break;
}
for (x=0;x<numb+1;x++) {
printf("\n::# %d",mult(x,2));
}
printf("\n\n%d",numb_address);
free(numb_address);
numb_address=0;
PracticeStrings();
getchar();
return 0;
}
int mult (int x, int y)
{
return x*y;
}
The PracticeStrings function on line 26 is the issue currently. When I compile, it displays Hello Student 0: before accepting the input (from fgets). I'm using Code::Blocks to compile.
Any help would be appreciated!
Edit...
Hahaha, yes, I understand that my program is inefficient and very silly. As you can tell, it doesn't really accomplish much. It is mostly just something to shove what I'm currently learning and try to apply things without actually rewriting the code examples (what do I learn if I copy word for word?). Anyways, thanks for the help! I guess that does make sense! It is too bad that my tutorials didn't mention that, I'm sure it is something that just takes a little bit of a higher understanding. I'm sure that the tutorial writer didn't expect anyone to mix the functions in the way I did.
Thanks a ton guys! Hopefully I can get used to this. I've done lots of scripting and plenty in the .net languages, hopefully I can add C to this list :)
It is because when you read the number:
scanf("%d", &numb);
stdin still has \n left in the buffer. So when you call PracticeStrings() and subsequently:
fgets(FirstPeriod[0]->name, 256, stdin);
You read \n and end up with
FirstPeriod[0]->name[i] == '\0';
Further, as you are learning, learn to validate :)
I.e.:
if ((foo = malloc(blah)) == NULL) {
... err ...
And even more critical:
if (scanf(..) != number_of_items_i_want) {
... did not get a number, or what ever I wanted ...
etc.
I think your issue is due to the behavior of your console, and your scanf() call.
The default setting for your console is probably line buffering. That means that nothing you type on your terminal is sent to stdin until after you have hit the enter key.
However, your call to scanf() (in main()) is only grabbing the integer that you've typed - not the trailing carriage return. Your carriage return is still sitting, unread, in stdin until the fgets() call in line 26.
One way around that is to get scanf() to consume the trailing carriage return too:
scanf("%d%*c", &numb);
Which reads the integer from stdin into &numb, and reads (and discards) an extra character.
This all hilights one of the big problems with the use of scanf(), which is how to make it cope in the event that you get a string that you weren't expecting.
A safer way is to use a combination of fgets() and sscanf(). The former will let you read a string from a file (as you've done), and the latter will run a formatting string over it.
eg.
char temp[20];
fgets(temp, 20, stdin);
sscanf(temp, "%d", &numb);

C Programming Input Error

int main(void) {
char *input;
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
prompt>input
RUN FAILED (exit value 138, total time: 3s)
What's wrong with the code? Has to be either the scanf() or the second printf(). The input is of unknown length. A lot people have said to simply create a char array of length 'X' to hold the input. Just wanted to know then why this code works.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
Your specific problem is that you have no storage behind input. It's an uninitialised pointer, pointing to a random spot in memory, which is unlikely to be anywhere useful.
You can use something like:
char *input = malloc (100);
// check that input != NULL
// use it
free (input);
or:
char input[100];
but you have a serious problem with your use of scanf (see below).
You should never use an unbounded %s in scanf (or any of its variants unless you totally control the input). It's a dangerous practice prone to buffer overflows and the sooner you get out of the habit, the better. It's akin to gets() in that way.
From an earlier answer of mine, this piece of code below (along with your main code incorporated into it) provides a safe way of getting user input. You pass in an optional prompt, the buffer to load the input into, and the size of the buffer.
It will return the input up to the size of the buffer (stripped of the newline if there) then clear out the rest of the line if necessary so that it doesn't affect the next input operation. It will return either OK or an error indication on end-of-file or if the input was too long (you still get the first part of the input in case you want to do something with it).
Once you have the line, you can sscanf it, safely, to your heart's content. However, that's not required in your case since you're only trying to get a string. Just use the buffer that's returned directly.
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
int main(void) {
char input[10];
int rc = getLine ("prompt> ", input, sizeof (input));
switch (rc) {
case NO_INPUT: printf ("\nNo input recieved\n"); break;
case TOO_LONG: printf ("Too long, truncated input below:\n");
default: printf("Your input was [%s]\n", input);
}
return 0;
}
Give that a shot, it's far more robust than using scanf("%s") on its own.
As for your update asking why this works:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
It's undefined code. Period. You only allocate space for a character but you scan in a string. Since a string is a character array of all the characters followed by a zero character, the only string you could input safely there would be an empty one.
Anything else will write to both the character and whatever happens to be adjacent to the character on the stack.
This is no different to allocating char input[100] then entering 200 characters, it's still buffer overflow and should be avoided.
Discussion below is based on a particular implementation of C, not necessarily all implementations.
Chances are, you got lucky here. Compilers may generate code that keeps the stack pointer aligned so that, even though you asked for one byte, you may get space allocated for four (or even more, depending on the architecture - I'll assume most types are four bytes here for simplicity).
In addition, you may find that you can also safely overwrite the eight bytes of argc integer and argv pointer (they're probably still there even though you don't use them, no point having two different sets of start-up code just to save a few bytes on the stack).
If you write further than that, you'll eventually overwrite the return address from main to your start-up code. Then you'll know about it since your code will go off into la-la land when main exits.
With undefined behaviour, anything can happen. Sometimes that anything includes the possibility that it will work perfectly (similar to "throw a deck of cards in the air often enough and they'll eventually fall in a nice neat sorted heap" but a little less random).
That does not make undefined behaviour any less of a bad thing.
char *input;
Is only a pointer - there is no data space allocated store the data that scanf collects.
try this instead
char input[100];
You may want to try scanf("%c", input) inside of a while loop that has your delimiting character. You should also make input an array char input[X] where X is a number of sufficient value to hold the most likely values for your input. I would try making input an array first though.
You forgot to allocate the memory before using your pointer.
Try it:
int main(void) {
char input[256];
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
or even:
#include <stdlib.h>
#include <stdio.h>
int main(void) {
char *input = (char *) malloc(sizeof(char) * 256));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
What compiler do you use? In Turbo C 3.0 it works.
Try this variant:
#include <stdio.h>
#include <alloc.h>
int main(void)
{
char *input = (char*)calloc(100, sizeof(char));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
free(input);
return 0;
}
Try:-
int main(void) {
char input[100];
printf("prompt>");
scanf("%99s", input);
printf("%s", input);
return 0;
}
This will limit the string to 99 bytes. Note "%s" == string of characters delimited by white space or newline ie. you only get the first word!
I think what you really want is:
#include <stdio.h>
int main(void) {
char input[99];
printf("prompt>");
fgets(input,99,stdin);
printf("->%s<-", input);
return 0;
}
You probably need to add some code to get rid of unwanted new line characters!

Resources