I'm trying to read the following type of input
2
string1
string2
where the first line indicates the amount of strings following below, and the strings are all of (some) same length. Next, I'd like to print these strings in my program, which I was thinking of doing as follows.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_string_array(char** a, int size){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main()
{
int n;
scanf("%d", &n);
char* s;
scanf("%s", s);
int l = strlen(s);
char input[n][l];
strcpy(s, input[0]);
for (int i = 1; i < n; i++) {
scanf("%s", s);
strcpy(s, input[i]);
}
print_string_array(input, n);
}
But I get the following warnings and error.
main.c: In function ‘main’:
main.c:24:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
24 | print_string_array(input, n);
| ^~~~~
| |
| char (*)[(sizetype)(l)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(l)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
Segmentation fault (core dumped)
Why isn't my array input recognized as a char** type? And how would I go about fixing this without removing the general properties of my current program (for example, adaptability to any length of input strings)?
EDIT:
I've corrected some mistakes from not having coded in C for years (which may be a war crime from what I've seen in the comments):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void print_string_array(char** a, int size){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main(){
int n;
scanf("%d", &n);
char s[100]; // large enough buffer
scanf("%s", s);
int l = strlen(s);
char input[n][l+1]; // +1 to leave room for ‘\0’ character?
strcpy(input[0], s);
for (int i=1; i<n; i++){
scanf("%s", input[i]);
}
print_string_array(input, n);
for (int i=0; i<n; i++){
free(input[i]);
}
free(input);
}
But I still get some errors and warnings which I would like to solve.
main.c: In function ‘main’:
main.c:22:24: warning: passing argument 1 of ‘print_string_array’ from incompatible pointer type [-Wincompatible-pointer-types]
22 | print_string_array(input, n);
| ^~~~~
| |
| char (*)[(sizetype)(n)]
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(n)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
Segmentation fault (core dumped)
Starting with the warnings, obviously I change the type of a from char** to something else. However, should I really give it the type char (*)[(sizetype)(n)]?? Also, there's the problem of segmentaion fault which is happening somewhere in the for loop.
Besides the problems in your code that are explained in the comments.
input is a char* that points to an array in memory that is of size n*l and not a char**, which is a pointer to a char*.
You would need to allocate an array of char*[] and then add each char* pointer that you get from scanf to that array.
The Variable Length Array input[n][l+1] does not need to be free'd.
The input[n][l+1] array is not a pointer to pointer **a. There are differences in the memory arrangement and they are not compatible.
void print_string_array( int size, int len, char (*a)[len]){ gives the compiler the dimensions of the VLA so the function can access it correctly.
scanf("%99s", s); will limit the input to no more than 99 characters. There is a problem in limiting input in scanf("%s", input[i]); to avoid putting too many characters into input[i].
#include <stdio.h>
#include <string.h>
void print_string_array( int size, int len, char (*a)[len]){
for (int i=0; i<size; i++){
printf("%s\n", a[i]);
}
}
int main(){
int n;
scanf("%d", &n);
char s[100]; // large enough buffer
scanf("%99s", s);
int l = strlen(s);
char input[n][l+1]; // +1 to leave room for ‘\0’ character?
strcpy(input[0], s);
for (int i=1; i<n; i++){
scanf("%s", input[i]);
}
print_string_array(n, l + 1, input);
}
Maybe this will help you out. It shows an example of dynamic string allocation
char buffer[101];
printf("Enter your name: ");
// Stores the name into auxiliary memory
scanf(" %100[^\n]", buffer);
// Creates a dynamic string
char* name = (char *) malloc(strlen(buffer) + 1);
//or use char* name = strdup(buffer) as pointed out by #Cheatah in the comments
// Sets the value
strcpy(name, buffer);
printf("Your name is %s", name);
// Frees the memory
free(name);
If you are just to print the strings one after the other, as you receive them, there's no need to store the full set of strings (or even a complete string) to do the task, you can implement a simple (4 states) automaton to read the number of strings, then print the strings as you are receiving their characters (character by character). This allows you to handle any length strings (like hundreds of megabyte strings) and upto 4,294,967,295 strings. (more if I change the declaration of n) and you'll get a far more efficient program that starts printing as soon as possible, instead of reading everything before printing anything.
#include <stdio.h>
#include <stdlib.h>
#define IN_STRING (0)
#define AFTER_NUMBER (1)
#define IN_NUMBER (2)
#define PRE_NUMBER (3)
#define F(_fmt) "%s:%d:%s:"_fmt, __FILE__, __LINE__, __func__
#define ERR_TAIL(E_fmt, ...) do { \
fprintf(stderr, _fmt, ##__VA_ARGS__); \
exit(1); \
} while(0)
#define ERR(ERR_fmt, ...) \
ERR_TAIL(F("ERROR: "_fmt), ##__VA_ARGS__)
int main()
{
int c, /* to hold the char */
last_char = EOF, /* to hold the prvious char */
status = PRE_NUMBER; /* state of the automaton */
unsigned n = 0; /* number of strings to read */
while ((c = fgetc(stdin)) != EOF) {
switch (status) {
case PRE_NUMBER:
switch(c) {
case ' ': case '\n': case '\t':
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
status = IN_NUMBER;
n = c - '0';
break;
default: /* error */
ERR("Sintax error on input: non"
" digit character '%c' before "
"first number\n", c);
return 1;
} /* switch */
break;
case IN_NUMBER:
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n *= 10;
n += c - '0';
break;
case '\n':
status = IN_STRING;
break;
default:
status = AFTER_NUMBER;
break;
} /* switch */
break;
case AFTER_NUMBER:
switch (c) {
case '\n':
status = IN_STRING;
break;
case '\t': case ' ': /* ignored */
break;
default: /* error */
ERR("Sintax error on input: extra"
" character '%c' after first "
"number\n", c);
exit(1);
} /* switch */
break;
case IN_STRING:
switch (c) {
case '\n':
fputc(c, stdout);
if (!--n)
exit(0);
break;
default:
fputc(c, stdout);
break;
} /* switch */
break;
} /* switch */
last_char = c;
} /* while */
int exit_code = 0;
/* decide what to do when we receive a premature EOF */
switch(status) {
case PRE_NUMBER: /* before reading a number */
ERR("No number read before the strings\n");
exit_code = 1;
break;
case IN_NUMBER: /* in a number or in the spaces */
case AFTER_NUMBER: /* after the first newline */
fprintf(stderr,
"Nothing read after the number of strings\n");
exit_code = 1;
break;
case IN_STRING: /* IN_STRING, but */
if (last_char != '\n')
fputc('\n', stdout);
} /* switch */
return exit_code;
} /* main */
anyway, in your code:
char* s;
scanf("%s", s);
you cannot pass scanf() a pointer value that has not been initialized with enough memory to hold the string to be read.
On other side, beware that variable array declaracions (VAD) are controversial, as many compilers don't implement them and your code will not be portable, when you declare an array as VAD, you reserve space in the stack for the array, this being probably a mess if you end declaring very big arrays. The best and most portable way of declaring an array is to declare it with a constant expression (an expression that doesn't change at run time / an expression that is calculated by the compiler at compilation time) This is not your case, as you want to hold as big lines and as many as you like, with the only restriction that all the strings must have the same length as the first one (which you cannot enforce in any way)
One reason for the VADs being controversial is related to the following warning you have in your code
main.c:5:32: note: expected ‘char **’ but argument is of type ‘char (*)[(sizetype)(n)]’
5 | void print_string_array(char** a, int size){
| ~~~~~~~^
This informs you that a char ** is not the same type as a pointer to an array of n elements, on pointer decayment when passing it as parameter (the decayment happens only to the outer pointer, not to the inner ones). Decayment goes to the first level only, as the second/third/etc. are pointers to arrays, and so, the referred elements are not pointers, but arrays of n elements. When you increment a pointer char * or you do pointer arithmetic, you increment the address stored in that pointer variable by one because the pointed to type is an array. But when you increment a pointer char (*)[10] (a pointer to a ten element char array) you increment the address stored in that pointer by 10, so you cannot use pointer arithmetic, as you have declared it as a double pointer and it will be increased by sizeof (char *) (which is not what you want, 8 bytes, the size of a pointer)
Almost all the things commented lead you to Undefined Behaviour, and it is normal that you are getting that error. If I hade to write your code (and conserve the strings before doing anything) I would use dynamic memory with malloc(3) and realloc(3) as I parse the input.
Related
I'm supposed to make a program that replaces vowels in a string for numbers, without using and using pointers.
I used the commented printf in each switch statement to debug my program, and the output when the string is: aeiou, is:
4eiou
3iou
1ou
0u
2
and at the end when printing the string it just prints a blank line, when the output should be: 43102.
I'm doing something wrong that's replacing the complete string, but I can't figure it out. Can someone help me?
Thank you very much!
#include <stdio.h>
void changes(char* ptr) {
while (*ptr != '\0') {
switch(*ptr) {
case 'a':
*(ptr)='4';
//printf("%s\n", ptr);
break;
case 'e':
*(ptr)='3';
//printf("%s\n", ptr);
break;
case 'i':
*(ptr)='1';
//printf("%s\n", ptr);
break;
case 'o':
*(ptr)='0';
//printf("%s\n", ptr);
break;
case 'u':
*(ptr)='2';
//printf("%s\n", ptr);
break;
default:
break;
}
ptr++;
}
//Print the string
printf("%s\n", ptr);
}
int main() {
char sString[51];
char *charPtr = NULL;
charPtr = &sString[0];
printf("Introduce a string: ");
scanf("%[^\n]s", sString);
changes(charPtr);
}
You incrementing the pointer and printing what it points to using %s format specifier of printf. Keep a pointer to the beginning of the string and print it. You will see the desired behavior.
char *s = ptr;
while(*ptr != 0){
..
printf("%s",s);
}
This will print the whole string.(And you can notice the changes that you have made).
So... the main question is how I can use the string that the user entered in another function? I know it would be a lot easier to do it all in the main function but we are forced to use as many separate ones as possible. Thanks in advance.
Following on from the comment, you most likely want to declare the str in a scope available to both functions:
int enterWord (char *str) {
...
scanf("%24s", str);
...
return str[0];
}
int menuScan (char *str) {
...
}
int main (void) {
char str[25] = {0};
int someint;
...
someint = menuScan (enterWord (str));
return 0;
}
or
int main (void) {
char str[25] = {0};
int someint, someotherint;
...
someint = enterWord (str);
...
someotherint = menuScan (str);
return 0;
}
You may want to employ a bit of additional error checking on the user input as well, e.g.:
int enterWord (char *str) {
printf ("Please enter a single word that is no more than 25 characters: ");
if (scanf ("%24s", str))
printf ("\nThanks! You entered: %s", str);
else
return -1;
return str[0];
}
...
int main (void) {
char str[25] = {0};
int someint, someotherint;
...
if ((someint = enterWord (str)) = -1) {
fprintf (stderr, "enterWord() error: input failure.\n");
return 1;
}
...
someotherint = menuScan (str);
return 0;
}
Remaining Issue With '\n' Left In Input Buffer
Your remaining problems come from the fact that after you call scanf, you are leaving the '\n' (cause by pressing [Enter]) in the input buffer stdin. The next time your program calls scanf it takes the '\n' left in the input buffer as the user input. (if you check, you will find it is using the value 0xa (or 10) which is the value for newline)
You have two options. You can use a loop to empty stdin:
int c;
while ((c = getchar()) != '\n' && c != EOF) {}
You can also use the assignment suppression operator of scanf to read and discard the newline, e.g.:
scanf ("%24[^\n]%*c", str)
Where %24[^\n] read upto 24 chars (not including the '\n' into str) and %*c which reads and discards a single character (the newline). That way your input buffer is empty before the next user input.
Here is a short working example:
#include <stdio.h>
int enterWord (char *str);
void menuOptions ();
int menuScan (char *str);
int main (void) {
char str[25] = {0};
if (enterWord (str) == -1) {
fprintf (stderr, "enterWord() error: input failure.\n");
return 1;
}
do {
menuOptions();
} while (!menuScan (str));
return 0;
}
int enterWord (char *str)
{
printf ("Please enter a single word that is no more than 25 characters: ");
if (scanf ("%24[^\n]%*c", str))
printf ("\nThanks! You entered: %s", str);
else
return -1;
return str[0];
}
void menuOptions ()
{
printf("\n\n========= MENU =========\n\n");
printf("Key Function\n");
printf("=== ========\n");
printf(" C Count the letters\n");
printf(" V Count the vowels\n");
printf(" R Reverse the word\n");
printf(" P Check if the word is a palindrome\n");
printf(" W Enter a new word\n");
printf(" Z Exit\n\n");
}
int menuScan (char *str)
{
/* always initialize variables */
char *p = str;
char menuChoice = 0;
int c = 0;
int charcnt = 0;
printf ("Please enter a character from the options above: ");
if (!scanf ("%c%*c", &menuChoice)) {
fprintf (stderr, "menuScan() error: input failure.\n");
return -1;
}
printf ("\nYou entered: %c\n", menuChoice);
c = menuChoice; /* I don't like to type */
/* validate input */
if (c < 'A' || ('Z' < c && c < 'a') || 'z' < c) {
fprintf (stderr, "menuChoice() error: input is not [a-z] or [A-Z]\n");
return -1;
}
/* convert to lowercase */
if ('A' <= c && c <= 'Z') c += 32;
switch (c) {
case 'c':
for (; *p; p++) charcnt++;
printf ("\n\nThere are '%d' letters in '%s'\n", charcnt, str);
break;
case 'z':
return -1;
default : printf ("(%c) invalid choice -> try again.\n", c);
}
return 0;
}
Compile
gcc -Wall -Wextra -finline-functions -O3 -o bin/menuscan menuscan.c
Example/Use
$ ./bin/menuscan
Please enter a single word that is no more than 25 characters: 0123456789
Thanks! You entered: 0123456789
========= MENU =========
Key Function
=== ========
C Count the letters
V Count the vowels
R Reverse the word
P Check if the word is a palindrome
W Enter a new word
Z Exit
Please enter a character from the options above: c
You entered: c
There are '10' letters in '0123456789'
========= MENU =========
Key Function
=== ========
C Count the letters
V Count the vowels
R Reverse the word
P Check if the word is a palindrome
W Enter a new word
Z Exit
Please enter a character from the options above: z
You entered: z
There are a lot of problems with your code, but I will address only the actual question you posed.
When you have a function which creates a result value to be used somewhere else, you need to return that value when the function ends. The 'return' keyword will do this, but you must bear in mind that the thing being returned must continue to exist after the function has ended (as noted by #David C. Rankin in the comments).
Locally declared variables will cease to exist when the function ends, so the solution is to declare them in a wider scope.
// declare the string in a wider scope
// provide one extra character space for the string terminator \0 character
char inputStr[25 + 1];
// pass the string to the function which will fill it with the entered string
// NOTE: to avoid risk of someone entering too many letters in the string, we
// also pass in the length of the string buffer
enterWord(inputStr, 25);
The changes to the enterWord function would be:
void enterWord(char* str, int length){
printf("Please enter a single word that is no more than %d characters: ", length);
// this should verify the length of the entered text to make sure it isn't too long... but that's not your question
scanf("%s", str);
printf("\nThanks! You entered: %s", str);
}
In the scope where you declared inputStr, the string will now contain the data entered by the user.
In this case we are returning the string from the function by a different mechanism than the 'return' keyword. Here we are passing a pointer to the first letter of the buffer space, so that the function will fill the original inputStr buffer from inside the function.
If you must use a more 'functional' coding paradigm, you might want to consider allocating space for the buffer on the heap using 'malloc', you would then need to remember to use 'free' at a later point in the code to release that allocated memory and avoid a memory leak, which is why that would not be my preferred solution in this case.
If I execute the exec() function in another C program as a main function it works perfectly, while if I put it as a function called in the main menu it gives me some warning and the function does not run.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> /* for fork */
#include <sys/types.h> /* for pid_t */
#include <sys/wait.h> /* for wait */
int exec (void) {
char array[100];
char character;
int i = 0;
char* point;
int j = 0;
printf ("Digita una stringa");
printf ("\n");
do {
character = getchar();
array[i] = character;
i++;
}
while (character != '\n');
array[i-1] = '\0';
i = 0;
char* string[100];
char *word = strtok(array, " .");
j = 0;
while (word != NULL) {
printf("%s\n", word);
string[j++] = word; // Increment j
word = strtok(NULL, " .");
}
string[j] = NULL; // Make sure the array is NULL term
printf ("\n");
pid_t pid;
pid = fork();
int status;
if (pid == -1) {
perror("");
}else if (pid == 0) {
execvp(string[0], string); /* execute the command */
fprintf(stderr, "Failed to exec");
exit(1);
}
else {
//.. wait until the child ends
waitpid(-1, &status, 0);
}
return;
}
int read_input (void) {
int choice;
printf("Seleziona una voce dal menu");
do {
printf("\n");
scanf ("%i", &choice);
if (choice > 8 || choice < 1)
printf ("Attenzione, inserisci un valore contemplato dal menu");
}
while ( choice > 8 || choice < 1);
return choice;
}
void main (int argc, char *argv[]) {
printf ("------------------------\n");
printf (" MENU \n");
printf ("------------------------\n");
printf (" \n");
printf ("1) Esecuzione in foreground di un processo\n");
printf ("2) Ctrl -C\n");
printf ("3) Exit\n");
printf ("4) Background\n");
printf ("5) Pipe\n");
printf ("6) Jobs\n");
printf ("7) fg\n");
printf ("8) kill\n");
int menu = read_input();
switch (menu) {
case '1' :
exec ();
break;
case '2' :
//ctrl();
break;
case '3' :
//exit_();
break;
case '4' :
//background();
break;
case '5' :
//pipe();
break;
case '6' :
//jobs();
break;
case '7' :
//fg();
break;
case '8' :
//kill();
break;
}
}
this is the warning:
elaborato.c:31:16: warning: initialization makes pointer from integer without a cast [enabled by default] char *word = strtok(array, " .");
Regarding the problem related to input,
do {
printf("\n");
scanf ("%i", &choice);
if (choice > 8 || choice < 1)
printf ("Attenzione, inserisci un valore contemplato dal menu");
}
while ( choice > 8 || choice < 1);
Once you type an integer and press enter, the scanf() consumes the number and a newline is left in stdin. Next time the loop goes around (assuming input <1 or >8 or something else) scanf gets that newline and it goes on.
add a getchar() after the scanf().
The answer is in the warnings, you should move them from the comment into the question.
elaborato.c:31:16: warning: initialization makes pointer from integer without a cast [enabled by default] char *word = strtok(array, " .");
That means that word, which is a char pointer is being initialized from an integer. Therefore, it seems strtok() is returning an integer... that doesn't sound right.
From the strtok() man page:
#include <string.h>
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
That seems right, it returns a char *.... but it also says it's declared in <string.h>... which you aren't including. Since it's not defined, the compiler assumes it as int strtok().
Fix: add the #include <string.h> line.
The problem you are seeing is that of scanf getting skipped.
For more details you can refer here
The call to scanf() after the printf consumes the new-line character and continues without the user having to enter anything.
It reads the very next character from standard in, which is probably a newline character and thus not prompting you for any input.
I'm too tired to comment on the entire code (it is really bad), so I'll just write about the issue in question and how trivially it could be debugged.
First thing to do is to check if we get the number and return to main, hence:
int menu = read_input();
printf("got [%d]\n", menu);
Running this:
[snip]
1
got [1]
So we indeed get to this point.
As such now we check what is this compared to.
int menu = read_input();
printf("got [%d] '1'=[%d]\n", menu, '1');
Let's run:
1
got [1] '1'=[49]
So, menu stores an integer 1, while '1' is a character code for 1 in ascii, which, well, is not an integer 1.
In general I don't see what was the problem with narrowing it down.
EDIT: solved it, turns out I should use %c not %s because foodSelect and foodSize are characters not strings :P thanks
I'm trying to pass 3 values to the function output: foodChoice, foodSelect, foodSize (and foodOrderNum, and foodSubtotal but I haven't gotten around to that yet).
However, when I try to printf foodSelect, I get a segmentation fault, but when I try to print foodChoice, I don't. When I try to printf foodSize it just shows nothing.
source:
#include <stdio.h>
#include <string.h>
void question (char choice[]);
int output(char *foodChoice, char *foodSelect, char *foodSize);
void question (char choice[]) {
char choiceYesNo;
char *foodOptions;
char *foodChoice;
char *foodSelect;
char *foodSize;
int foodOrderNum = 0;
float foodSubtotal = 0;
switch (choice[0]) {
case 'f':
foodChoice = "Fish";
foodOptions = "(K- Haddock, T- Halibut)";
break;
case 'c':
foodChoice = "Chips";
foodOptions = "(C- Cut, R- Ring)";
break;
case 'd':
foodChoice = "Drinks";
foodOptions = "(S- Softdrink, C- Coffee, T- Tea)";
break;
}
printf("Do you order %s? (Y/N): ", foodChoice);
scanf("%c", &choiceYesNo);
printf("%s choice %s: ", foodChoice, foodOptions);
scanf("%s", &foodSelect);
printf("What size (L - Large, M - Medium, S - Small): ");
scanf("%s", &foodSize);
printf("How many orders do you want? (>=0): ");
scanf("%d", &foodOrderNum);
output(foodChoice, foodSelect, foodSize);
}
int output(char *foodChoice, char *foodSelect, char *foodSize) {
// printf("You ordered %s: %s - SIZE: %s amount ordered: , subtotal price: \n",
// foodChoice, foodSelect, foodSize);
printf("\n\n%s\n", foodSelect);
// printf("\n\n%s\n", foodSelect);
}
int main() {
question("chips");
}
You haven't allocated memory for:
char *foodOptions;
char *foodChoice;
char *foodSelect;
char *foodSize;
Do malloc and allocate memory. Note that:
char *foodChoice="Fish";
And
char *foodChoice;
foodChoice="Fish";
are not the same.
This is because you pass &foodSelect to scanf, which is incorrect for C strings. You should pass foodSelect instead, no ampersand.
You should also allocate sufficient space to store the values the users enter, and instruct scanf on the max size of the buffer.
#define MAX_BUF 128
...
char foodSelect[MAX_BUF];
...
scanf("%127s", foodSelect);
#include<stdio.h>
#include<stdlib.h>
#define n ((sizeof(char)) * 100 )
int stringlength(char * str)
{
int count=0;
while(*str)
{
if(*str == '\n')
{
*str=0;
}
else
count++, str++;
}
return count;
}
int palin1(char *str, int k)
{
char * pend = str + k - 1;
if(*pend != *str)
return 0;
else
palin1(str+1, k-1);
return 1;
}
int palin(char *str)
{
int length = stringlength(str), f=0;
char *pend = str + length - 1;
while(str <= pend)
{
if(*str == *pend) f=1;
else
return (f = 0);
str++, pend--;
}
return 1;
}
main()
{
char * ps = (char *)malloc(n);
int flag;
if(ps == NULL) printf("Malloc Fail\n");
else
{
printf("Malloc Succeeded, you have memory of %d bytes\n", n);
printf("This program checks if String is Palindrome or not\n\
\nEnter your String: ");
fgets(ps, 100, stdin);
printf("You entered: %s of length %d", ps, stringlength(ps));
int i = 0;
printf("\n\nEnter:\n1.Using iteration\n2.Using Recursion ");
scanf("%d", &i);
switch(i)
{
case 1:
flag=palin(ps);
break;
case 2:
flag=palin1(ps,stringlength(ps));
break;
default:
printf("Invalid input");
}
if(flag) printf("\nYou entered a Palindrome");
else printf("\nNot a Palindrome");
}
free (ps);
return 0;
}
Why does the above program http://www.ideone.com/qpGxi does not give any output on putting the input:
mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
I know fgets(ps,100,stdin) will take only 100 characters and not more than that, but why does the program halt execution?
You should check for fgets failure, as recommended by the fgets spec.
if ( fgets(ps,100,stdin) == NULL ) {
printf("Input failed.");
//check for 'feof' or 'ferror' here
return -1;
}
printf("You entered: %s of length %d",ps,stringlength(ps));
I don't see why fgets would be failing, but you would get an uninitialized character buffer back, which would crash printf.
EDIT: You should really pay attention to your compiler warnings, too.
prog.c:49: warning: return type defaults to ‘int’
prog.c: In function ‘main’:
prog.c:59: warning: ignoring return value of ‘fgets’, declared with attribute warn_unused_result
prog.c:63: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result
prog.c: In function ‘palin’:
prog.c:46: warning: control reaches end of non-void function
prog.c: In function ‘main’:
prog.c:52: warning: ‘flag’ may be used uninitialized in this function
You can see that even your compiler recommends checking fgets for null. Also, flag should be set to 0 in the default case, otherwise you will get undefined behavior if the user enters something other than 1 or 2.
EDIT 2: Oh for Christ's sake! your program works fine! You forgot to check "run program" in Ideone!!!
http://www.ideone.com/7ecZd
You cannot break a string literal just like that
printf("%s\n", "string literal **WRONGLY**\n
broken right after the line break.");
What you can do is use the preprocessor feature of joining successive string literals to make just one
printf("%s\n", "string literal **CORRECTLY**\n"
"broken because the preprocessor joins these 2 parts.");
It's terminating because there are characters left in the input stream if the input is too large. For example, if you wish to take only 5 characters using fgets but have given the input as -
StackOverflow
Overflow are left in the input stream. They need to be removed from the stream for further input operations to succeed. So, remove those extra characters from the stream using -
fgets(ps,100,stdin);
while (getchar() != '\n');
Since the input stream is struck with offending characters, the scanf statement that actually takes the user input is not working and jumping to subsequent operations.
Also initialize the flag variable to 0 other wise it has garbage values.