I got a question.
I want to have a FOR loop that prints back text many strings. Lets say I type my forename and last name. And a FOR loop produce the strings.
#include <stdio.h>
int main(){
char str1 [12];
char str2 [12];
char wordarray [2]={str1,str2}; // error here
int i;
printf ("Type your forname : ");
scanf ("%s",&str1);
printf ("\nType your last name : ");
scanf ("%s",&str2);
printf ("\n\nYour name is : ");
printf ("%s\t%s",str1,str2);
printf ("\n");
for (i=0;i<3;i++){
printf ("%s",wordarray [i]); // Error here .
} // end FOR
return 0;
} // end MAIN
You need to validate each read with scanf (or whatever function you use for user input) to insure you have valid data to work with. You should also provide a width limitation for the read to insure you do not read beyond the end of your array. (e.g. scanf ("%11s", str1)). You should look into using fgets for user input and remove the '\n' included by fgets in your buffer. This will help you avoid a number of pitfalls with scanf that usually plague new users, especially when taking mixed string and numeric input.
Other than that, you should also look to avoid using magic numbers in your code (e.g. char str1[12]). If you need a constant 12, then define one or declare an enum to create it.
Putting those pieces together, you could do something like:
#include <stdio.h>
#define LEN 12
int main (void) {
char str1 [LEN] = "";
char str2 [LEN] = "";
char *wordarray[] = {str1, str2};
int i, nwords = sizeof wordarray/sizeof *wordarray;
printf ("Type your forname : ");
if (scanf ("%11s", str1) != 1) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
printf ("Type your last name : ");
if (scanf ("%11s", str2) != 1) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
printf ("\nYour name is : %s %s\n", str1, str2);
for (i = 0; i < nwords; i++){
printf ("%s", wordarray [i]);
}
putchar ('\n');
return 0;
}
Example Use/Output
$ ./bin/name
Type your forname : david
Type your last name : rankin
Your name is : david rankin
davidrankin
Look things over, and consider the other answers and let me know if you have further questions. Also take my comment regarding zero input or input beyond 12 characters into consideration. This will help build robustness into your input handling.
If you would like to approach the input using fgets, you can improve your input handling a bit with the following:
#include <stdio.h>
#include <string.h>
#define LEN 12
int main (void) {
char str1 [LEN] = "",
str2 [LEN] = "",
*wordarray[] = {str1, str2};
size_t i, len = 0, nwords = sizeof wordarray/sizeof *wordarray;
printf ("Type your forname : ");
if (!fgets (str1, LEN, stdin)) { /* read with fgets/validate */
fprintf (stderr, "error: invalid input.\n");
return 1;
}
len = strlen (str1); /* get length of str1 */
if (str1[len-1] == '\n') /* test for trailing '\n' */
str1[--len] = 0; /* overwrite with nulbyte */
printf ("Type your last name : ");
if (!fgets (str2, LEN, stdin)) {
fprintf (stderr, "error: invalid input.\n");
return 1;
}
len = strlen (str2);
if (str2[len-1] == '\n')
str2[--len] = 0;
printf ("\nYour name is : %s %s\n", str1, str2);
for (i = 0; i < nwords; i++){
printf ("%s", wordarray [i]);
}
putchar ('\n');
return 0;
}
You don't understand how array and pointer work. You should read this answer.
#include <stdio.h>
int main(void) {
printf("Type your forname : ");
char str1[12];
{ // we open a scope because ret don't need to be in function scope
int ret = scanf("%11s", str1); // scanf need to know how many bytes are
// available without count `\0` and you must send the array itself not the
// address
if (ret != 1) { // scanf don't set str1
fprintf(stderr, "Error in input\n"); // stderr is the error stream
return 1;
}
}
printf("\nType your last name : ");
char str2[12];
{
int ret = scanf("%11s", str2);
if (ret != 1) {
fprintf(stderr, "Error in input\n");
return 1;
}
}
printf("\n\nYour name is : ");
printf("%s\t%s", str1, str2);
printf("\n");
char *word[2] = {str1, str2}; // we need an array of pointer
for (size_t i = 0; i < sizeof word / sizeof *word; i++) { // size of array
printf("%s", word[i]);
}
return 0;
}
Shure I dont know how everything functions. That why I ask :) Thanks for the reply. I will investigate. With this information I will try to build a larger FOR-loop , so I can insert values in a 2D array. The user can add values to a 2d array then change the information text or numbers in the slots.
#include <stdio.h>
#define lenght 12 // corrected, define string format lenght
int main(){
char str1 [lenght]; // corrected, strings should have format lenght
char str2 [lenght]; // corrected, strings should have format lenght
char *wordarray [2]={str1,str2}; // corrected, add a * to wordarray[2]
int i;
printf ("Type your forname : ");
scanf ("%s",str1); // corrected, skip the & in ("%s",&str1);
printf ("Type your last name : ");
scanf ("%s",str2); // corrected, skip the & in ("%s",&str2);
printf ("\n\nYour name is : %s\t%s\n",str1,str2);
for (i=0;i<2;i++){ // corrected, i<2 must match the array elements
printf ("%s\t",wordarray [i]);
} // end FOR
return 0;
} // end MAIN
Ok. Had another go.
Havent worked much with strings. This program has both strings and numbers in arrays and printed in FOR loops. I also tried to get the indevidual elements in the arrays available to the user, so he could change the values.
I guess my style is pretty wretched. but ... its what I got.
Now concerning the GETS (str1), obtaining a string from the user. At the first use in the program it behaves normal. but the second time in the program I had to use GETS ("%s", str1) so it behaved proper. also an issue was to add specific numbers from a array detremined by the user. displayed in a for loop...
Another issue is to CLEAR the console screen after the JUMP . so the text doesnt flood the screen.
Comment : I agree David C. Rankin that validation of user data is important. Only tolerate character inputs on string requests, and numbers on integer request. Also return false input if "special characters" like slash or dots. I tried to read the origonal K&R C book and they talked about it, topics like turning all letters to small case or big case. but I had troubles getting the example code to run, maybe a C89 C11 compiler issue, I dont know.
#include <stdio.h>
//#include <string.h> // GCC32-C . mingw . compile
#define lenght 20 // Orbit_L75.Apartment_9
int main(){
int i,j,k,select,select2,*ptr;
char str1 [lenght];
char str2 [lenght];
char *wordarray [2]={str1,str2}; // character array must have a * asterix pointer .
int numarray [2];
printf ("Type your forname : ");
gets (str1); // gets (wordarray[0]) // alternative syntax
printf ("Type your last name : ");
gets (str2);
printf ("Enter your telephone number : ");
scanf ("%d",&numarray[0]); // assign a value to numarray slot 0
//scanf ("%d",(numarray+0)); // alternative syntax
printf ("Enter your age : ");
scanf ("%d",&numarray[1]); // assign a value to numarray slot 1
printf ("\n\n");
jump1 :
printf ("=========================\n");
for (i=1;i<5;i++)
{printf ("%d\t",i);}
printf ("\n");
for (j=0;j<2;j++)
{printf ("%s\t",wordarray[j]);}
//printf ("%s\t",*(wordarray+j));} // alternative syntax
printf ("\n");
for (k=0;k<2;k++)
{printf ("%d\t",numarray[k]);}
printf ("Sum = %d\n",(numarray[0]+numarray[1])); // add numarray slot 0 and slot 1.
//printf ("Sum = %d",*(numarray+0)+*(numarray+1)); // alternative syntax
printf ("=========================\n");
printf ("\n\nSelect\n1: Change Telephone \n2: Change Age \n3: Change First Name \n4: Change Last Name \n5: RAM location\n");
scanf ("%d",&select);
if (select == 1)
{printf ("New number : ");
scanf ("%d",&numarray[0]);
//scanf ("%d",(numarray+0)); // alternative syntax
printf ("\n");}
else if (select == 2)
{printf ("New age : ");
scanf ("%d",&numarray[1]);
printf ("\n");}
else if (select == 3)
{printf ("New First Name : ");
scanf ("%s",str1); //problems with the display using GETS on the second run.
printf ("\n");}
else if (select == 4)
{printf ("New Last Name : ");
scanf ("%s",str2);
printf ("\n");}
else if (select == 5)
{ // select2
{printf ("\nRAM location of : \n\t1. Telephone number\n\t2. Age\n\t3. First Name.\n\t4. Last Name\n");}
scanf ("%d",&select2);
if (select2 == 1)
{ptr = &numarray[0];
printf ("\nTelephone number\nValue in Decimal\t: %d\nValue in Hexadecimal\t: %ph\nRAM location in decimal\t: %d\nRAM location in Hex\t: %ph\n\n\n",*ptr,*ptr,ptr,ptr);}
else if (select2 == 2)
{ptr = &numarray[1];
printf ("\nAge\nValue in Decimal\t: %d\nValue in Hexadecimal\t: %ph\nRAM location in decimal\t: %d\nRAM location in Hex\t: %ph\n\n\n",*ptr,*ptr,ptr,ptr);}
else if (select2 == 3)
{ptr = &wordarray[0];
printf ("\nFirst Name\nValue in Text\t: %s\nValue in Hexadecimal\t: %ph\nRAM location in decimal\t: %d\nRAM location in Hex\t: %ph\n\n\n",*ptr,*ptr,ptr,ptr);}
else if (select2 == 4)
{ptr = &wordarray[1];
printf ("\nLast Name\nValue in Text\t: %s\nValue in Hexadecimal\t: %ph\nRAM location in decimal\t: %d\nRAM location in Hex\t: %ph\n\n\n",*ptr,*ptr,ptr,ptr);}
else if (select2 <1 || select2 > 4)
{printf ("\nValue is out of range, Try again .\n\n");}
} // end IF select2
else if (select <1 || select > 5)
{printf ("\nValue is out of range, Try again .\n\n");}
goto jump1;
return 0;
} // end MAIN
str1 and str2 are effectively pointers.
wordarray is an array of chars. It should be an array of pointers to char.
Also in your scanf you're passing address of str1 and str2, but you should just pass str1 and str2.
Related
I am new to C. I allocated memory with this statement:
patientptr = (char*) calloc (118, sizeof (char));
then I assign data using this (this is a part of the function):
char name[51];
int age;
char agestr[3];
char infectiondate [11];
char address[51];
char *patientptr;
printf("\nEnter the patient name (50 characters at maximum): ");
scanf ("%50s", name);
*patientptr = name;
printf("Enter the patient age: ");
scanf ("%d", &age);
sprintf (agestr, "%2d", age);
*(patientptr + 51) = agestr;
printf("Enter the patient date of infection (in form of dd/mm/year): ");
*(patientptr + 54) = scanf ("%10d", infectiondate);
printf("Enter the patient address (50 characters at maximum): ");
*(patientptr + 65) = scanf ("%50s", address);
*(ptrsptr+patientsnum-1) = patientptr;
printf ("\nPatient added.\n");
Everything goes fine except that after the "enter the patient address: " line, it prints the "patient added" line directly without waiting to scan the address. the output is like this:
Enter the patient name (50 characters at maximum): ahmed
Enter the patient age: 20
Enter the patient date of infection (in form of dd/mm/year): 10/10/2020
Enter the patient address (50 characters at maximum):
Patient added.
is the wrong with my allocated memory?
You may well have used calloc to allocate some memory but examine this snippet:
char *patientptr;
printf("\nEnter the patient name (50 characters at maximum): ");
scanf ("%50s", name);
*patientptr = name;
That first line shadows whatever patientptr was with an uninitialised pointer, hence the final line is undefined behaviour (patientptr now points to some arbitrary address). All bets are off at this point, anything is possible.
Fix that and try again.
In addition, it looks like you believe that:
*(patientptr + 51) = agestr;
is a way to copy a C string from one place to another. In actual fact, this will attempt to place the agestr pointer value into the single character at the memory location &(patientptr[51]), and possibly should have warned you about this.
You need to look into strcpy for this, something along the lines of:
strcpy(patientptr + 51, agestr);
But, if you're looking to do user input, it's often a good idea to work around the limits of scanf. It does, after all, stand for "scan formatted" and there's very little that's less formatted than user input.
I have a favourite function I use for this, which is shown below, along with the modifications to your own code to use it (using both that function and with quite a bit of other validation specific to your case):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
// Bullet-proof line input function.
#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;
}
// Ensure a character array is non-empty and all digits.
int checkDigits(char *arr, size_t sz) {
if (sz == 0) {
return 0;
}
while (sz-- > 0) {
if (! isdigit(*arr++)) {
return 0;
}
}
return 1;
}
// Get customer data line, return NULL if okay, error if not.
// Output record must be long enough for format string below
// and a one-character end-string marker.
static char *getPatientData(char *patientData) {
// Keep this format string in sync with field sizes below.
static char *fmtString = "%-50.50s" "%3d" "%-10.10s" "%-50.50s";
char name[51];
char ageStr[4];
char infectionDate[11];
char address[51];
if (getLine("Patient name: ", name, sizeof(name)) != OK) {
return "Error getting name.";
}
if (getLine("Patient age: ", ageStr, sizeof(ageStr)) != OK) {
return "Error getting age.";
}
if (! checkDigits(ageStr, strlen(ageStr))) {
return "Error, age contains non-digit data.";
}
int age = atoi(ageStr);
// Further age sanity checking, if desired. Example: ensure <= 150.
if (getLine("Infection date (dd/mm/yyyy): ", infectionDate, sizeof(infectionDate)) != OK) {
return "Error getting infection date.";
}
if (
strlen(infectionDate) != 10
|| infectionDate[2] != '/'
|| infectionDate[5] != '/'
|| ! checkDigits(infectionDate, 2)
|| ! checkDigits(infectionDate + 3, 2)
|| ! checkDigits(infectionDate + 6, 4)
) {
return "Error, incorrect format.";
}
// Further checking if desired. Example: valid year/month/day combo.
if (getLine("Patient address: ", address, sizeof(address)) != OK) {
return "Error getting address.";
}
sprintf(patientData, fmtString, name, age, infectionDate, address);
return NULL;
}
int main(void) {
char *patientPtr = malloc (50 + 3 + 10 + 50 + 1);
char *result = getPatientData(patientPtr);
if (result != NULL) {
printf("*** %s\n", result);
return 1;
}
printf("Got '%s'\n", patientPtr);
return 0;
}
A sample run follows:
Patient name: Pax Diablo
Patient age: 55
Infection date (dd/mm/yyyy): 25/05/2020
Patient address: No fixed abode
Got 'Pax Diablo 5525/05/2020No fixed abode '
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.
I'm looking for a way to write an input loop that continues to print prompts until the user enters a blank line.
This is what I want to do:
Loop starts, prints prompt > to the command line. User enters a line that ends with '\n', my program does whatever with that line, and then prints > again. This continues until the user enters a blank line (\n), at this point the loop terminates.
Would something along these lines answer your needs?
int ret;
// Basically, in order, 1 to indicate the file descriptor of the standard output
// ">" as the string you want to print
// 1 as the number of characters you want printed.
write(1, ">", 1);
while ((ret = read(0, buff, SizeBuff)) > 0) {
buff[ret] = 0;
if (buff[0] == '\n' && strlen(buff) == 1)
return (0);
/*Do your stuff*/
write(1, ">", 1);
}
A very simple scanf version can also be used:
#include <stdio.h>
#define MAXL 64
int main (void) {
char str[MAXL] = {0};
printf ("\n Enter a string ([enter] alone to quit)\n");
while (printf (" > ") && scanf ("%63[^\n]%*c", str) == 1)
{
/* do whatever in your code */
printf (" result: %s\n", str);
}
return 0;
}
Use/Output
$ ./bin/scanf_enter_quits
Enter a string ([enter] alone to quit)
> string
result: string
> another
result: another
>
Note: MAXL-1 added as maximum width specifier for scanf to prevent write beyond end of array.
getline Example
getline by dynamically allocating the line buffer allows you to accept a line as long as you want to give it. It can be billions of characters (up to the extent of your memory). This is a strength and a weakness. If you need to limit the amount of data you accept, it is up to you to check/validate/etc....
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *str = NULL;
size_t n = 0;
ssize_t nchr = 0;
printf ("\n Enter a string ([enter] alone to quit)\n");
while (printf (" > ") && (nchr = getline (&str, &n, stdin)) > 1)
{
str[--nchr] = 0; /* strip newline from input */
printf (" (str: %s)\n", str); /* do whatever in your code */
}
if (str) free (str);
return 0;
}
Use/Output
$ ./bin/getline_enter_quits
Enter a string ([enter] alone to quit)
> string one as long as you want
(str: string one as long as you want)
> string 2 make it 1000 chars.........................................
(str: string 2 make it 1000 chars.........................................)
>
scanf Dynamic Allocation
You can also have scanf dynamically allocate the space for you by using the m conversion specifier (older versions of scanf use the a conversion specifier for this purpose). You must also provide a pointer-to-pointer to accept the address in this case. (e.g. scanf ("%m[^\n]%*c", &str) ).
#include
#include
int main (void) {
char *str = NULL;
printf ("\n Enter a string ([enter] alone to quit)\n");
while (printf (" > ") && scanf ("%m[^\n]%*c", &str) == 1)
{
printf (" (str: %s)\n", str); /* do whatever in your code */
if (str) free (str); /* you must free each loop */
str = NULL;
}
if (str) free (str);
return 0;
}
Use/Output
$ ./bin/scanf_dyn_enter_quits
Enter a string ([enter] alone to quit)
> some string as long as you want
(str: some string as long as you want)
> another string any length .......... ............. .............
(str: another string any length .......... ............. .............)
>
Practice.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARR 32
int main(void){
int MEM=64;
char arr[ARR],*p=(char *)calloc(MEM,(sizeof(char))),*q=NULL;
int i=0,j=1;
printf("\nEnter String : ");
while(j){
scanf(" %[^\n]s " ,arr);
if(j==1)
strcpy(p,arr);
else
strcat(p,arr);
if((j*ARR)==MEM){
MEM=MEM+(j*ARR);
q=realloc(p, MEM);
if(!(q)){
printf("\nNOT ENOUGH MEMORY\n");
goto END;
}
p=q;
}
for(i=0;i<(strlen(arr));++i){
if(arr[i]=='\n')
break;
}
if(arr[i]=='\n')
break;
++j;
}
printf("\n %s\n",p);
END: free(p);p=NULL;q=NULL;
return 0;
}
I am trying to get multiple string inputs.
I am using scanf(" %[^\n]s",arr); to take the input instead of fgets(arr,ARR,stdin);, because with fgets the program execution stops as soon as I hit ENTER key. But with scanf(" %[^\n]s",arr); the program is unable to get out of the while() loop even after entering \n.
I would like to know the mistake or mistakes I have made while writing the code.
The canonical way of reading multiple lines of input in C is to use fgets in a loop, like
while (fgets(arr, sizeof(arr), stdin) != NULL)
{
if (arr_contains_special_input_to_exit_loop(arr))
break;
// Optionally check for and remove trailing newline from input
// Append `arr` to your data
}
The condition to exit the loop might be some special input or an empty line or something else completely.
One mistake is:
for(i=0;i<(strlen(arr));++i){
if(arr[i]=='\n')
break;
}
Looking earlier in you code you have:
scanf(" %[^\n]s " ,arr);
The [^\n] prevents any newlines \n from being contained in arr. So your loop that looks for (arr[i]=='\n') will never find any. Your next bit of code continues looking for non-existent newlines:
if(arr[i]=='\n')
break;
This last break also breaks out of your outer loop preventing you from asking for further input on finding a newline (which it shouldn't). Fix these issues and it should get much further allowing you to enter multiple items.
Edit:
With a bit of effort looking at what you were doing, I now have it taking multiple input and reallocating as necessary. The strings are all concatenated and printed at the end. It could still stand a bit of work, but this should give you a few hints:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARR 32
int main (void) {
int MEM = 64;
char arr[ARR], *p = (char *) calloc (MEM, (sizeof (char))), *q = NULL;
int i = 0, j = 1;
while (j) {
printf ("\nEnter String : ");
scanf (" %[^\n]s ", arr);
printf (" you entered (arr): %s\n", arr);
if (strcmp (arr, "q") == 0) {
printf ("\n 'q' entered, exiting.\n\n"); // provide for exit if `q` entered
break;
}
if (j == 1)
strcpy (p, arr);
else
strcat (p, arr);
if ((j * ARR) == MEM) {
MEM = MEM + (j * ARR);
q = realloc (p, MEM);
if (!q) {
printf ("\nNOT ENOUGH MEMORY\n");
goto END;
}
else
printf ("\nMemory Reallocation - succeeded.\n");
p = q;
}
++j;
}
printf (" %s\n", p);
END:
if (p) free (p); /* always test pointer before calling free */
p = NULL;
q = NULL;
return 0;
}
output:
./bin/me
Enter String : fishinsea
you entered (arr): fishinsea
Enter String : alligators
you entered (arr): alligators
Memory Reallocation - succeeded.
Enter String : really_big_mosters
you entered (arr): really_big_mosters
Enter String : SuperSnake_Prudhome
you entered (arr): SuperSnake_Prudhome
Memory Reallocation - succeeded.
Enter String : 8_puppies
you entered (arr): 8_puppies
Enter String : q
you entered (arr): q
'q' entered, exiting.
fishinseaalligatorsreally_big_mostersSuperSnake_Prudhome8_puppies
Here is my code to print the string
char accname[MAX][MAXSTRING], transname[MAX][MAXSTRING];
printf ("Enter title for new account: ");
accname[i][i] = validatestring();
printf ("\n");
printf ("Enter title for transaction: ");
transname[i][i] = validatestring();
printf ("\n");
printf ("%s %s", accname[i], transname[i]);
my code for validatestring()
char validatestring() {
int keeptrying = 1, rc;
char i[31];
do
{
rc = scanf("%30[^\n]", &i);
if (rc == 0)
{
printf (" **Invalid input try again: ");
clear();
}
else if (getchar() != '\n')
{
printf (" **Title is longer than 30 characters: ");
clear();
}
else
{
keeptrying = 0;
}
} while (keeptrying == 1);
return i;
}
at the printf stage for accname[i] / transname[i] i don't get the value I entered, I get weird conversion string types, sometimes I got the first character of my input but now I get something completely different. Can anyone figure out why?
Your validatestring function is hopelesely broken.
Firstly, you declared validatestring as returning char. Yet you attempt too return a char * from it (see return i, where i is char [31]). This should not even compile.
Secondly, if you intend to return a string from validatestring, you have to make sure that you are not returning a pointer to a local buffer from it. i is a local array. A pointer to i cannot be returned from validatestring.
Yeah that is because what you are doing is trying to store everything in one char.
array[i][i]
which is a character position in which you are trying to store everything in it
I think what you intend to do is
*array[i] // It is a pointer to that location which you referring to.
This will store your string in array[i] from which you can access your characters using
array[i][i]
I hope this solves your problem.Also your function should return a char pointer char*.
This should do it:
*accname[i] = validatestring();
Also change the return type of your function to char*