c gets/fgets isnt working - c

gets doesn't work in the function neuePerson,
it worked when it was in a for loop, but then I changed it and now the compiler says isn't undefined.
I tried it with fgets, now there is no warning, but it still ignores fgets, so I cant write anything in the console.
in the main function's gets works. I'm a little bit confused... :o
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "readline.h"
//typedef struct Person {
// char name[50];
// char unit;
// int number;
//} Person;
typedef struct person {
char name[50];
char unit;
int number;
struct person *next;
} Person;
void neuePerson(Person *firstPerson) {
time_t t;
time(&t);
srand((unsigned int)t);
while (firstPerson->next != 0)
firstPerson = firstPerson->next;
printf("Gib einen Namen ein \n");
fgets(firstPerson->name, 50, stdin);
firstPerson->number = rand() % 99 + 1;
firstPerson->unit = rand() % 3 + 65;
firstPerson->next = (Person*)malloc(sizeof(Person));
firstPerson = firstPerson->next;
firstPerson->next = 0;
}
void ausgabe(Person *anfang) {
while (anfang->next != 0) {
printf("Name: %s", anfang->name);
printf(" Abteilung: %c", anfang->unit);
printf(" Tel.Nummer: %i\n", anfang->number);
anfang = anfang->next;
}
}
int main() {
Person* pers1 = (Person*)malloc(sizeof(Person));
//Person* test = (Person*)malloc(sizeof(Person));
//gets(test->name, 50);
//printf("%s", test->name);
pers1->next = 0;
char z = 'n';
while (z != 'e') {
printf("[n]eue Person, [a]usgabe, [e]nde");
z = getchar();
if (z == 'n') neuePerson(pers1);
else if (z == 'a') ausgabe(pers1);
}
}

The problem comes from the line buffering of standard input:
You read the option in main with getchar(), but the byte is returned to your program after you type the enter key. Only the initial char from the line is returned, the rest stays in the stream.
When you subsequently read the person's name with fgets(), it returns an empty line because it gets the \n that is still in the stream. Contrary to popular belief, fflush(stdin) is not the solution because it has undefined behavior. A better solution is to read the option this way:
int main() {
Person *pers1 = (Person*)malloc(sizeof(Person));
pers1->next = NULL;
pers1->unit = 0;
pers1->name[0] = '\0';
for (;;) {
int z, c;
printf("[n]eue Person, [a]usgabe, [e]nde ");
z = c = getchar();
while (c != EOF && c != '\n')
c = getchar();
if (z == EOF || z == 'e')
break;
else
if (z == 'n')
neuePerson(pers1);
else
if (z == 'a')
ausgabe(pers1);
}
}
You should improve your list handling: an empty list should be just NULL, it is incorrect to keep a dummy uninitialized structure pending at the end of the list. You can handle the update to the list head by passing a pointer to the head to neuePerson.

I agree with chqrlie's answer; in addition, don't forget to free up your list at after you exit the main while loop:
int main()
{
/** your While loop */
Person *nextp = pers1;
do {
free(nextp);
nextp = nextp->next;
} while (nextp != NULL);
}
It would be a good idea to separate the linked-list logic from everything else. You'll be glad you did now and when your program becomes larger.
Also, Become friends with valgrind.

First, since you asked about both gets and fgets, that enables me to quote from the man page :
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
I am going to take the liberty of re-writing your code to the minimal set, before I answer your question. You're testing gets, so I can remove everything afterward, and everything in your code that isn't called before gets. I'll also move your call to fgets from neuePerson to main. I'll also avoid heap memory to simply further, I trust you to figure out how to use the heap properly. Finally, I really don't like using uninitialized structs or main routines that don't have exit codes, so I'll do that as well. That looks like this :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "readline.h"
typedef struct person{
char name[50];
char unit;
int number;
struct person* next;
} Person;
int main() {
Person _pers1, *pers1 = &_pers1;
char z = 'n';
memset(pers1, 0, sizeof(Person));
while (z != 'e') {
z = getchar();
pers1->name = fgets(pers1->name, 50, stdin);
}
return 0;
}
At a high level, the problem is that you have two methods that handle strings in different ways. You've already been shown a solution that takes one of the methods - getchar - and makes it work like another method - fgets with a buffer size of 1 in this case. But there may well be many situations where you do not have enough information about both methods to do this. In this situation, for instance, if you did not know that newline characters were in the input feed at all, or you were programming in a language where fgets had a programmable stop rather than just stopping on a newline character, your original approach may have been more sensible.
So in this situation, when two methods aren't cooperating, it's often a good idea to use the same method throughout. That looks like this :
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "readline.h"
typedef struct person{
char name[50];
char unit;
int number;
struct person* next;
} Person;
int main() {
Person _pers1, *pers1 = &_pers1;
char z[50];
memset(pers1, 0, sizeof(Person));
memset(z, 0, sizeof(char) * 50);
while (z[0] != 'e') {
fgets(z, 50, stdin);
fgets(pers1->name, 50, stdin);
}
return 0;
}
Making z 50 bytes big is of course overkill. I did this to illustrate a principle. If you use the same method the same way everywhere, you won't run into problems. You don't need to ask questions like "wait does z need to be 1 or 2 bytes? Should I call fgets with 2 or 1?". You already know "50 is the most I'll allow input to be". You can come back and optimize later, if there ends up being a reason to optimize.
I also want to mention, it's true that this line,
while (z[0] != 'e') {
has some flaws. It would be more correct to look at values other than 'e' . I'd recommend 0, EOF, '\n', and '\r'. But the only one of those you could have known about in advance is 0, since you set that. It would be best, in my opinion, to discover that the others needed to be added through testing and using your code, rather than to "kitchen sink" your code to avoid problems before they happen.

Related

Dynamical Allocation & Structs - allocating memory dinamically to a string from a struct

I've got a problem regarding Dynamical Allocation & Structs.
The task: I have a struct of students, which looks like that:
typedef struct{
unsigned id;
char *lastName;
float grade;
}students_t;
I'm not allowed to pass to lastName a maximum number of characters, it must remain a pointer which size I will increase every time.
My code looks like this:
unsigned counter = 0;
students_t* students = NULL;
students_t temp;
char char_current;
unsigned char_counter=0;
while (fscanf(inputFile,"%u",&temp.id) == 1) {
students = realloc(students,(counter+1) * sizeof(students_t));
students[counter].id=temp.id;
printf("%d",students[counter].id);
students[counter].lastName = NULL;
while (fscanf(inputFile,"%c",&char_current) != ' ') {
students[counter].lastName = realloc(students[counter].lastName,(char_counter+1) * sizeof(char));
students[counter].lastName[char_counter] = char_current;
char_counter++;
}
students[counter].lastName[char_counter] = '\0';
fscanf(inputFile,"%f",&students[counter].grade);
counter++;
}
My problem is with the fscanf from the while (because the program enters an infinite loop), but I don't know how to actually fix it.
I would be grateful if someone could help me figure it out.
Thank you!
You have several problems:
The while() loop isn't terminating (your initial question).
fscanf() is unsafe - there are better alternatives.
You're using fscanf() incorrectly.
Reading a string a character at a time is inefficient.
Repeatedly calling "realloc()" is inefficient - there are better alternatives.
Here is some example code.
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define MAX_STRING 80
typedef struct {
unsigned id;
char *lastName;
float grade;
} students_t;
students_t* enter_new_student (FILE *inputFile)
{
char buffer[MAX_STRING];
unsigned id;
int iret;
// Check for end of input
iret = fscanf(inputFile, "%u", &id);
if ((iret < 1) || feof(inputFile)) { // iret should be "1" if successful
return NULL;
}
// Allocate a record and read its data
students_t *student = (students_t *)malloc(sizeof(students_t));
iret = fscanf(inputFile, "%s %f", buffer, &student->grade); // iret should be "2" if successful
student->id = id;
student->lastName = strdup(buffer); // strdup() does an implicit "malloc()" and "strcpy()"
// Return new student
return student;
}
int main()
{
students_t *student = NULL;
int record_counter = 0;
FILE *fp;
// Open file
if (!(fp = fopen("tmp.txt", "r"))) {
perror("unable to open file");
return 1;
}
// Read student records
while ((student = enter_new_student(fp))) {
if (student) {
++record_counter;
printf("new student=%s,id=%u, grade=%f, record_counter=%d\n",
student->lastName, student->id, student->grade, record_counter);
}
}
// Done
printf("Done: final record count=%d\n", record_counter);
return 0;
}
Here is a sample "tmp.txt" file:
1 Johnson 4.0
2 Jackson 3.5
3 Jamison 3.85
And corresponding sample output:
new student=Johnson,id=1, grade=4.000000, record_counter=1
new student=Jackson,id=2, grade=3.500000, record_counter=2
new student=Jamison,id=3, grade=3.850000, record_counter=3
In general, prefer using fgets() over fscanf(): Disadvantages of scanf
Notice that I put everything having to do with reading a student record inside a separate function: enter_new_student(). You'll also notice that the "control structure" - the "while loop" is OUTSIDE of the function.
There are two (related) conditions that can cause the loop to exit:
Didn't read "id"
End of file
The reason your original "while loop" failed was that fscanf() will never return ' ' ... so you inadvertently coded an "infinite loop". Here's why:
https://linux.die.net/man/3/fscanf
Return Value
These functions return the number of input items successfully matched and assigned, which can be fewer than provided
for, or even zero in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either
the first successful conversion or a matching failure occurs. EOF is
also returned if a read error occurs, in which case the error
indicator for the stream (see ferror(3)) is set, and errno is set
indicate the error.

Reading From Stdin Twice in C

int getLineCount() {
int ret = 0;
char c;
while ((c = fgetc(stdin)) != EOF)
if (c == '\n')
ret++;
return ret + 1;
}
void fill(char *WORD) {
int charIndex = 0;
char c;
while ((c = fgetc(stdin)) != EOF) {
*(WORD + charIndex++) = c;
}
}
int main() {
int lineNum = getLineCount();
char *WORD = (char*)calloc(lineNum * 18,sizeof(int));
fill(WORD);
return 0;
}
Here is the part of my code, and my question is(as you can see):
I'm trying to read stdin's content twice, but after the getLineCount function, it stays at the EOF and I can't read it again in fill function.
Im taking stdin from the user with this command in Linux;
$./output < text_file.txt
Is there any way to roll back stdin to starting character? If not, how can I fix this problem?
Thanks.
You can use rewind(stdin) to set the stream back to the start of file, but be aware that it is not guaranteed to work, especially if the stream is a pipe, a terminal or a device.
Your allocation scheme is incorrect: you could compute the size of the file and then allocate that many bytes, but your current (char*)calloc(lineNum * 18,sizeof(int)); allocates 18 times the size of type int for each line. Some files with short lines will fit in this array while others will invoke undefined behavior.
Note that c must be defined as int for c = fgetc(stdin); to properly store all values including the EOF special value.
Don't use rewind.
You can, of course, save the data you read from stdin (potentially in a file if it's too large for main memory) and operate on that.
Another possibility is this:
struct callback {
void (*call) (char, void *);
void * data;
};
void with_characters_from(FILE * file, struct callback const * callbacks, size_t count) {
int c;
while ((c = fgetc(file)) != EOF) {
char character = c & 0xFF;
for (size_t i = 0; i < count; ++i) {
callbacks[i].call(character, callbacks[i].data);
}
}
}
You inverse control, such that no longer your functions are "pulling data out of" stdin, but rather the data (characters) are "pushed to" them. Note that this can lead to callback hell, and in C you sacrifice a good portion of type safety (as well as code clarity .. no first class functions / closures ... sigh).
A small test:
struct counter_data {
char const character;
unsigned count;
};
void counter (char character, void * vptr) {
struct counter_data * data = vptr;
if (character == data->character) {
++(data->count);
}
}
int main() {
struct counter_data data [2] = {
{'a', 0}, {'x', 0}};
struct callback callbacks [2] = {
{&counter, &(data [0])},
{&counter, &(data [1])}};
with_characters_from (stdin, callbacks, 2);
printf("Counted %c %u times \n", data [0].character, data [0].count);
printf("Counted %c %u times \n", data [1].character, data [1].count);
return 0;
}
As already noted, for your particular example, you should consider a completely different approach: If possible compute the required size beforehand. If you exceed that size (which you should always test for), then use realloc in order to get a larger chunk of memory.

Parsing input in C and automatically allocating space for characters

I started learning programming with Python a couple months ago, and I decided to learn C because I am interested in lower level languages that let me interact closer to the computers hardware. I'm trying to get some input from a user in C, and I am writing my own little input parser. I'm having some trouble here:
#include <stdio.h>
char prompt()
{
char resp[]; // Create a variable for the users response
for (int i = 0; i < 1000; ++i)
{
char letter = getchar(); // Get character
if (letter == '\n') // If the user hits enter break the loop
{
break;
}
else // Otherwise append the character to the response array
{
resp[i] = letter;
}
}
return resp[]; // Return the response array
}
int main() {
return 0;
}
I'm receiving errors with this code. The errors specifically say:
error: definition of variable with array type needs an explicit size or an initializer
char resp[];
I take it that I must define a set value for an array or assign it something right away. I don't understand how I can grow the character array as the user types the input if arrays in C must have a defined value. I am thinking that using pointers or memory management might work, but I haven't learned a lot about these things yet so if you do have a solution involving pointers, it would be of great help to me if you could briefly explain what the code is doing. In the meantime I will try and find a solution.
You probably want to allocate memory, here's how you would do it>
#include <stdio.h>
#include <stdlib.h>
char* prompt()
{
char* resp; // Create a variable for the users response
int i;
resp = malloc(sizeof(char));//allocate space for one char
for (i = 0; i < 1000; ++i)
{
resp = realloc(resp, sizeof(char)*(i+1));//allocate space for one more char
char letter = getchar(); // Get character
if (letter == '\n') // If the user hits enter break the loop
{
break;
}
else // Otherwise append the character to the response array
{
resp[i] = letter;
}
}
return resp; // Return the response array
}
int main() {
char* answer = prompt();
printf("answer is %s\n", answer);
return 0;
}
And this will work but it is highly NOT recommended to do it like this because you never free() your allocated memory.
EDIT>
How to do it? You might want to avoid creating a new function and do it all in your main(), in that case, when you no longer need your variable simply call free(resp);
There isn't a dynamic runtime in C. You need to explicitly allocate resources because your code essentially translates directly into machine instructions.
Here's an example.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
int prompt(const size_t bufsize, char response[bufsize]) {
if (fgets(response, bufsize, stdin) == NULL)
return -1; // error
return 0;
}
int main() {
const size_t bufsize = 1024;
char* response = malloc(bufsize); // Create a variable for the users response
if (!response)
return -1; // error
if (prompt(bufsize, response))
return -1; // error
printf("%s", response);
free(response);
return 0;
}

Reading from multi-lines STDIN in C : segmentation error or no reading at all

I am trying to read multiple lines from stdin, in which even lines are strings and odd lines are numbers separated by spaces. I'm trying to read the numbers as integers and the strings as... strings. It's part of a school project but it's not the entire thing; I managed the rest of the stuff but I can't manage to actually GET the strings and ints from stdin.
I add every name to experiments when i is even (I try to use it as a line number)
I tried using malloc to append a string n and store it as an int in a a 2d array data when I encounter a space, using int a to navigate through the line.
And then the printing part is just to try to show it works and.. it doesn't. I'm not busting any array's length and I felt like I watched out for malloc but I spent more than 15 hours on this part and nothing good is coming out of it. I wondered if someone could give me a hint.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char *experiments[100];
int data[10][20];
char name[101];
int i=0;
int j=0;
char *n;
char *g;
fgets(name, 100, stdin);
while ((strstr(name,"*** END ***")!=0)&&(name!=NULL)){
if((i%2)==0){
experiments[i/2]=name;
name[0]='\0';
}
else {
int a = 0;
while ((name[a]!='\n')&&(a<100)){
if (name[a]!=' '){
size_t len = strlen(n);
g = malloc(len + 1 + 1);
strcpy(g,n);
g[strlen(n)-2] = name[a];
g[strlen(n)-1] = '\0';
n[0]='\0';
*n = *g;
free( g );
a+=1;
}
else {
data[j][i]=*n;
j+=1;
n[0]='\0';
a+=1;
}
}
}
i+=1;
fgets(name,100, stdin );
}
int k=0;
for(k=0;k<=i;k+=1){
printf("printing\n");
printf("%s\n", experiments[k]);
if (experiments[k][0]=='\0') {
printf("oh shoot!");
}
}
return(0);}
You seem to have fundamental confusions regarding:
Do you know the saying "Give me six hours to chop down a tree and I will spend the first four sharpening the axe"? There are many problems here, and they're probably caused by a blunt axe. Whatever book you're using to learn C is failing to teach you. I recommend K&R 2E. Don't forget to do the exercises.
Yuck! Neither for nor return are functions! Please, for the love of life, if you want other people to read your code, make it presentable for them! It would help if your code were consistently indented, too.
Arrays (e.g. it's impossible for name!=NULL to evaluate false, so that expression is pointless), pointers and the implicit conversion from array to pointer that occurs in experiments[i/2]=name;. To clarify, every time you assign like that, the different elements will point to the same place, and the values stored within that place will be overwritten when you next call fgets.
malloc; you've used it in the wrong place, and the way you used it reinvents automatic storage duration (that is, all of your variables). You might as well just not use it at all.
fgets; its mode of failure leads to horrible crashes in your program.
Strings; see above.
Start by reading K&R 2E and doing the exercises as I mentioned earlier... Once you've completed that book I reckon you'll have a fine chance at filling in the blanks for this program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char *experiments[100] = { 0 };
int data[10][20] = { 0 };
char name[101] = { 0 };
size_t i = 0, j = 0;
fgets(name, sizeof name, stdin);
while (strstr(name,"*** END ***") != 0){
if(i%2 == 0){
experiments[i / 2] = malloc(strlen(name) + 1);
if (experiments[i / 2] == NULL) {
puts("OOPS! malloc failure!");
return 0;
}
strcpy(experiments[i / 2], name);
}
else {
/* XXX: I have no idea what any of this was meant to do *
* ... but it was all HORRIBLY WRONG so I removed it. *
* Try again once you've read K&R 2E and done the *
* exercises... */
}
i++;
fgets(name, sizeof name, stdin);
}
for (size_t k = 0; k < i / 2; k++){
puts("Printing...");
puts(experiments[k]);
if (experiments[k][0] == '\0') {
puts("oh shoot!");
}
free(experiments[k]);
}
return 0;
}

Deallocation of Dynamic Arrays?

Here's the code I am working with...
while(temp[i]!=0){
while(temp[i]!=3){
FrameBuffer[a]=temp[i];
i++;
a++;
}
FrameBuffer[a]=temp[i];
printf(" Framebuffer: %s ", FrameBuffer);
result=layer1(FrameBuffer,PacketAction);
i++;
a=0;
}
The problem is that I want FrameBuffer to be reset each time it goes through the inner while loop (Size of FrameBuffer is 0 at start of loop). I've tried using free(FrameBuffer) but I get an error because I free the array more than once. I also tried writing FrameBuffer=NULL, but that did not work. Any help would be greatly appreciated. Thank you!
If you just need to initialise FrameBuffer before the start of each inner loop, memset can be used-:
while(temp[i]!=0) {
memset(FrameBuffer, 0, sizeof(FrameBuffer));
while(temp[i]!=3) {
Since you don't show the declarations or give a particularly good description of the input string, temp, it is a bit hard to know what you're up to.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
extern int somefunc(const char *fb, int pa);
extern int layer1(const char *fb, int pa);
int somefunc(const char *temp, int PacketAction)
{
int rc = 0;
char *FrameBuffer = calloc(2048, sizeof(char));
if (FrameBuffer != 0)
{
int i = 0;
while (temp[i] != '\0')
{
int a = 0;
while (temp[i] != 3)
FrameBuffer[a++] = temp[i++];
FrameBuffer[a++] = temp[i++];
FrameBuffer[a] = '\0';
assert(a < 2048);
printf("Framebuffer: %.*s\n", a, FrameBuffer);
int result = layer1(FrameBuffer, PacketAction);
if (rc == 0)
rc = result;
}
}
return rc;
}
This is probably sufficient. The function layer1 gets a null terminated string in FrameBuffer (it has no other visible way of determining how long the data is).
Note that by declaring a in the scope of the outer loop, I don't need to reinitialize it at the end of the loop. I've used a++ and i++ to increment the counters; it allows for compact notation with no loss of readability to the experienced C programmer — though I concede it can be a little more difficult for novice programmers to handle. Nevertheless, the idiom is worth learning.
I wonder if the inner loop should check for '\0' as well as 3 (aka '\3' or '\003'); I would need to know whether nulls can ever appear in temp other than at the very end. The code shown takes a lazy way out of validating for no overflow of the FrameBuffer. It would be better still if the function was told the length of the input temp:
void somefunc(const char *temp, size_t templen, int PacketAction)
The code could be written more resiliently. It could probably use strlen(temp), but it isn't absolutely clear from the available information.

Resources