#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void displayString (const char *sPtr);
void getString (char *[]);
int determinIfConvert (char);
int main ()
{
char originalString[11] = { 0 };
char convertedString[11];
getString (originalString);
displayString (originalString);
// this loop runs through the "originalString" to check for the char: 'a'
for (int i = 0; i < 11; i++) {
determinIfConvert (originalString[i]);
}
system ("pause");
}
void getString (char *a[]) // this function gets a string
{
printf ("enter 11 char string: \n");
scanf ("%s", a);
}
// this program displays the inputstring
void displayString (const char *sPtr)
{
for (; (*sPtr != '\0'); ++sPtr) {
printf ("%c", *sPtr);
}
}
int determinIfConvert (char *a)
{
if (a == 97) // this is a test condition. The goal is to
// check for all lowercase, but now i'm
// only entering "aaaaa"
{
printf ("Works"); // if it prints multiple"works"
// then i can continue my program
// but it only prints ONE "works" and freezes.
}
}
At the moment I have a problem with my For Loop in main() not finishing. The goal is to enter a string of characters, and then check for lowercase ones. This will be done with the function DeterminIfConvert(char). However, when I run through the loop element by element, it freezes after the second element. My test data is "aaaa" and it prints the "aaaa," so I know that my first two functions work just fine. I get to the loop, it goes through the first element, prints "works" and then freezes. :/
Multiple mistakes
void getString(char *a[])
should be
void getString(char a[])
Since you're sending the base address of an array of char, not an array of pointer to char
char *a[]; // array of pointer to char
char a[]; // array of char
int determinIfConvert(char *a)
should be
int determinIfConvert(char a)
Since you're sending a char, not a pointer to char
char * a; // pointer to char
char a; // char
NOTE:
Use the standard definition of main()
int main(void) //if no command line arguments.
If you are inputting an 11-char string, then you should be doing:
char originalString[12] = { 0 };
This is because you need 1 more character to store the null character '\0'.
That is probably why in your function getString(...), the pointer exceeds the array bounds and might invoke undefined behavior.
Finally, your function prototype for getString(...) should be
void getString(char a[]); //without the *
In addition to the other answers, you have several other areas where you can improve your code.
Avoid using magic numbers in your code (e.g. 11). Instead define a constant for the maximum characters in your string #define MAXC 11 or you can use an enum instead enum { MAXC = 11 };
As it currently sits, you do not protect against overflowing your 11 character array (which means your user can enter no more than 10 characters plus room for the nul-terminating character). To protect against the user entering something more than 10, you should use a field-width specifier with scanf:
scanf ("%10s", a);
That doesn't solve your problems with scanf. You must check the return every time to insure the expected number of conversions takes place, e.g.:
if (scanf ("%10s", a) != 1) {
fprintf (stderr, " -> error: invalid input.\n");
exit (EXIT_FAILURE);
}
That's better, but using %s, you cannot read a string containing whitespace, and you are still leaving a trailing '\n' in the input buffer. If the users enters "my dog", you store "my" only. To fix part of the problem you can use a format specifier of "%10[^\n]%*c". However, you must protect against an endless-loop if the user presses [Enter] without other input. To resolve all issues, and prevent leaving the trailing newline in the input buffer, you can use something like:
int getString (char *a) // this function gets a string
{
int c, rtn = 0;
printf ("enter string (10 char or less): ");
while ((rtn = scanf ("%10[^\n]%*c", a)) != 1) {
if (rtn == EOF)
break;
fprintf (stderr, " -> error: invalid input, try again..\n");
printf ("enter string (10 char or less): ");
/* flush input buffer - to avoid endless loop */
while ((c = getchar()) != '\n' && c != EOF) {}
}
return rtn;
}
All of which expose the difficulties using scanf for user input. A better approach may be to use fgets (or getline) to read the complete line of input.
Regardless whether you use scanf or fgets, etc.. you must take a bit of time and care in writing your input handlers to insure you try and cover all ways a user could muck up input. Below fgets is used just to present an alternative. You should also choose a return type that allows you to tell whether you have successfully received input or not. It might as well be a useful return such as the length of the input taken, etc..
The remainder of your level of pointer indirection issues have been addressed by other answers. Putting it all together, you could do something like:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXC 11
void displayString (const char *sPtr);
int getString (char *);
int determinIfConvert (char);
int main (void)
{
char originalString [MAXC] = "";
// char convertedString[MAXC] = ""; /* currently unused */
if (!getString (originalString)) {
fprintf (stderr, "error: getString failed.\n");
return 1;
}
displayString (originalString);
// this loop runs through the "originalString" to check for the char: 'a'
for (int i = 0; i < 11; i++) {
determinIfConvert (originalString[i]);
}
system ("pause");
return 0; /* main() is type 'int' and returns a value */
}
int getString (char *a) // this function gets a string
{
char *p = a;
int c;
size_t len = 0;
printf ("enter string (10 char or less): ");
for (;;) {
p = fgets (a, MAXC, stdin);
if (!p) break; /* handle [CTRL+D] */
if (*p == '\n') { /* handle empty str */
fprintf (stderr, " -> error: invalid input, try again..\n");
printf ("enter string (10 char or less): ");
continue;
}
/* trim newline/flush input buffer */
len = strlen (p);
if (len && a[len - 1] == '\n')
a[--len] = 0;
else /* user entered more than 10 chars */
while ((c = getchar()) != '\n' && c != EOF) {}
break;
}
return (int) len;
}
// this program displays the inputstring
void displayString (const char *sPtr)
{
for (; *sPtr; sPtr++) {
printf ("%c", *sPtr);
}
putchar ('\n');
}
int determinIfConvert (char a)
{
if (a == 97)
printf ("Works\n");
return 0;
}
Example Use/Output
$ ./bin/getdispstr
enter string (10 char or less): my dog has fleas
my dog has
Works
$ ./bin/getdispstr
enter string (10 char or less):
-> error: invalid input, try again..
enter string (10 char or less): my dog has fleas, my cat has none.
my dog has
Works
With CTRL+D (EOF)
$ ./bin/getdispstr
enter string (10 char or less): error: getString failed.
There are many ways to do this, this is just an example. Look over all the answers and let me know if you have questions.
This
char originalString[11] = { 0 };
followed by this
for (int i = 0; i < 11; i++)
{
determinIfConvert(originalString[i]);
}
is causing the problem. You see the array of char does not have elements post index 0. And yeah I believe what you are trying to attempt with
getString(originalString); seems like you want to get originalString from user input which is not correctly executed in your case.
You pass object of type char to a function accepting char*
char originalString[11] = { 0 };
determinIfConvert(originalString[i]);
int determinIfConvert(char *a)
A string is nothing but a null terminated set of characters, so if you wish to have 11 characters in you string, you should be allocating 12 bytes to your
array, ie you may change :
char originalString[11] = { 0 };
to
char originalString[12] = "";
/* Here is the string is empty but because you use double quotes
* compiler understands that you are initializing a string, so '\0' is auto
* appended to the end of it by the compiler to mark the end of the string.
*/
So is the case with convertedString[11] change it to
char convertedString[12] = "";
Change
void getString(char *a[]);
to
void getString(char a[]); //char *a is also fine
Change
int determinIfConvert(char *a)
to
int determinIfConvert(char a) // You wish to check a character
You may wish to replace
scanf("%s", a);
with
fgets(a,12,stdin);
because scanf can't check for overflows but fgets can. Here you can have up to 11 characters in the string. If an overflow occurs, the rest of the input is trimmed and '\0' is assigned to the 12th byte.
You may wish to use the islower function to check is a character is lowercase. So you may change
if (a == 97)
to
if (islower(a)) // check if a character is lowercase.
Remember you may need to include the string.h header to use islower()
Related
In an effort of solving a textbook problem, I'm trying to create a case insensitive version of the function called strstr() which is in the C language. So far, I've run into two problems. The first problem being that when I make the case insensitive version of strstr() it worked, but it didn't stop at the first matching string and continued to return the string even if they didn't match.
strstr() is supposed to see the first instance of a matching character up to n counts specified and then stop. Like if I wrote: "Xehanort" in string A and "Xemnas" in string B and specified 4, as the number, it would return Xe.
The idea behind the case insensitive version is that I can write : "Xehanort" in one string and "xemnas" in the next string and have it return Xe.
However, I've run into a new problem in new code I've tried: the function doesn't seem to want to run at all. I've tested this and it turns out the function seems to be at a crash and I'm not sure how to make it stop.
I've tried editing the code, I've tried using different for loops but figured that the code doesn't need to be too sophisticated yet, I've also tried different code entirely than what you are going to read, but that resulted in the problem mentioned earlier.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAX 100
char *stristr4(const char *p1, const char *p2, size_t num);
int main() {
char c[MAX], d[MAX];
printf("Please enter the string you want to compare.");
gets(c);
printf("Please enter the next string you want to compare.");
gets(d);
printf("The first string to be obtained from \n%s, and \n%s is \n%s",
c, d, stristr4(c, d, MAX));
}
char *stristr4(const char *p1, const char *p2, size_t num) {
const char *str1 = p1;
const char *str2 = p2;
char *str3;
int counter = 0;
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
if (tolower(str1[i]) == tolower(str2[j])) {
str3[i] = str1[i];
counter++;
} else {
if (counter > 0) {
break;
} else
continue;
}
}
}
return str3;
}
The code you see will ask for the strings you want to input. Ideally, it should return the input.
Then it should do the stristr function and return the first instance of matching string with case insensitivity.
However, the function I've created doesn't even seem to run.
Your code has undefined behavior (in this case causing a segmentation fault), because you try to store the resulting string via an uninitialized pointer str3.
Standard function strstr returns a pointer to the matching subsequence, you should do the same. The third argument is useless if the first and second arguments are proper C strings.
Here is a modified version:
char *stristr4(const char *p1, const char *p2) {
for (;; p1++) {
for (size_t i = 0;; i++) {
if (p2[i] == '\0')
return (char *)p1;
if (tolower((unsigned char)p1[i]) != tolower((unsigned char)p2[i]))
break;
}
if (*p1 == '\0')
return NULL;
}
}
Notes:
function tolower() as other functions from <ctype.h> takes an int argument that must have the value of an unsigned char or the special negative value EOF. char arguments must be converted to unsigned char to avoid undefined behavior for negative char values. char can be signed or unsigned by default depending on the platform and the compilers settings.
you should never use gets(). This function is obsolete and cannot be used safely with uncontrolled input. Use fgets() and strip the trailing newline:
if (fgets(c, sizeof c, stdin)) {
c[strcspn(c, "\n")] = '\0'; // strip the trailing newline if any
...
}
A third string could be passed to the function and fill that string with the matching characters.
Use fgets instead of gets.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define MAX 100
int stristr4(const char* p1, const char *p2, char *same);
int main( void)
{
int comp = 0;
char c[MAX] = "", d[MAX] = "", match[MAX] = "";//initialize to all zero
printf ( "Please enter the string you want to compare. ");
fflush ( stdout);//printf has no newline so make sure it prints
fgets ( c, MAX, stdin);
c[strcspn ( c, "\n")] = 0;//remove newline
printf ( "Please enter the next string you want to compare. ");
fflush ( stdout);//printf has no newline so make sure it prints
fgets ( d, MAX, stdin);
d[strcspn ( d, "\n")] = 0;//remove newline
comp = stristr4 ( c, d, match);
printf ( "Comparison of \n%s, and \n%s is \n%d\n", c, d, comp);
if ( *match) {
printf ( "The matching string to be obtained from \n%s, and \n%s is \n%s\n"
, c, d, match);
}
return 0;
}
int stristr4 ( const char *p1,const char *p2, char *same)
{
//pointers not pointing to zero and tolower values are equal
while ( *p1 && *p2 && tolower ( (unsigned char)*p1) == tolower ( (unsigned char)*p2))
{
*same = tolower ( (unsigned char)*p1);//count same characters
same++;//increment to next character
*same = 0;//zero terminate
p1++;
p2++;
}
return *p1 - *p2;//return difference
}
my code would work in this way:
input : a[]="create /dir/bar"
and save in this string:
b[]=create
c[]=/dir/bar
there is also a case in which i save an other string: (for example)
a[]=write /foo/bar "test"
b[]= write
c[]=/foo/bar
d[]=test (without the "")
my code is this :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SPACE ' '
void divide(char a[], char b[], char c[], char d[]);
int main(int argc, char const *argv[]) {
char a[50+1];
char b[50+1];
char c[50+1];
char d[50+1];
int i;
scanf("%s\n", a);
divide(a, b, c, d);
for(i=0; b[i]!='\0'; i++)
printf("%s %s %s \n", b, c, d);
return 0;
}
void divide(char a[], char b[], char c[], char d[]){
int i, j;
for(i=0; a[i]!=SPACE; i++)
b[i]=a[i];
b[i]='\0';
for(; a[i]==SPACE; i++)
;
for(j=0; a[i]!='\0'; i++, j++)
c[j]=a[i];
c[j]='\0';
for(; a[i]==SPACE; i++)
;
if(a[i]=='"'){
i++;
for(j=0; a[i]!='"'; i++)
d[j]=a[i];
d[j]='\0';
return;
}
}
but it does not work for a segmentation fault after the program get the input. where is the problem?
I must not use malloc, because it spend too much time to work (I have to get thousands of these lines) and does not respect a limit. (I work for a project in my university)
You may be making this a little more difficult than it needs to be. Yes, you can tokenize a string by repeated calls to sscanf or with repeated reads with scanf, but the C library provides a tool to tokenize words from a line of text. Smartly enough named strtok.
You simply declare a constant string holding the delimiters you wish to break the words on (e.g. delims = " \t"; to break the words on space or tab, and then call strtok (str, delims) to return the first token (word), and then loop over repeated calls to strtok (NULL, delims) to parse the remaining words (or until you reach your max of 3 words).
(note the first call to strtok uses str as the first parameter, while all subsequent calls use NULL)
This is a far more flexible way to handle an unknown number of tokens in a string.
Instead of using a[], b[], c[], etc.. consider using just a single buf[] to read the line of input into, and then an array of strings to hold the parameters (which allows you to use an index variable during your loops over strtok to assign and copy the correct string to the associated index).
Don't use void as a return in circumstances like this. Why not use a meaningful return (like the number of parameters in the line of text). That way, you know how many were read (or tokenized) in your divide function. Give it a return that can provide useful information, e.g.
size_t divide (char *buf, char (*params)[MAXC+1]);
Which will now return a size_t type containing the number of parameters that result from each call to divide.
Putting it altogether, (and using fgets to read the entire line of input), you could do something like the following:
#include <stdio.h>
#include <string.h>
enum { MAXP = 3, MAXC = 50 }; /* max parameters & chars */
size_t divide (char *buf, char (*params)[MAXC+1]);
int main (void) {
char buf[MAXC * 4 + 1] = "";
char params[MAXP][MAXC + 1]; /* array to hold 3 parameters */
size_t i, len, nparams = 0;
/* use fgets for line-oriented user input */
printf ("\nenter commands: ");
if (!fgets (buf, sizeof buf, stdin)) {
fprintf (stderr, "error: insufficient input.\n");
return 1;
}
len = strlen (buf); /* get length */
if (buf[len - 1] == '\n') /* validate last char is '\n' */
buf[--len] = 0; /* overwrite with nul-terminating char */
else { /* short read -- handle error */
fprintf (stderr, "error: incomplete input read.\n");
return 1;
}
nparams = divide (buf, params);
for (i = 0; i < nparams; i++)
printf ("parameter[%zu] : %s\n", i, params[i]);
return 0;
}
/* divide using strtok */
size_t divide (char *buf, char (*params)[MAXC+1])
{
char *delims = " \t", /* delimiters for strtok */
*p = buf; /* pointer to buf */
size_t n = 0; /* var to return number of params */
p = strtok (buf, delims); /* tokenize fist paramter */
while (p) { /* now loop until all words exhausted or limit reached */
strncpy (params[n++], p, MAXC); /* copy token to params array */
if (n == MAXP) /* check if limit reached */
break;
p = strtok (NULL, delims); /* get next token */
}
return n; /* return the number of parameters found */
}
Example Use/Output
$ /bin/splitparams
enter commands: create /dir/bar
parameter[0] : create
parameter[1] : /dir/bar
$ ./bin/splitparams
enter commands: write /foo/bar "test"
parameter[0] : write
parameter[1] : /foo/bar
parameter[2] : "test"
Or providing a bunch of extra words (to validate handling of only 3)
$ ./bin/splitparams
enter commands: write /foo/bar "test" and some more stuff
parameter[0] : write
parameter[1] : /foo/bar
parameter[2] : "test"
If you run this simple program
#include<stdio.h>
int main(int argc, char const *argv[]) {
char a[50+1];
scanf("%s\n", a);
printf("|%s|\n", a);
return 0;
}
and give the input "create foo", you'll get the output
|create|
As you can see you only got the first word, i.e. "create", instead of the expected "create foo" as
scanf("%s\n", a);
will only give the first word. Consequently your divide function will fail. Instead of scanf you could do
fgets(a, 51, stdin);
to make sure the whole input is read into array a.
In general your program lacks a lot of range checking and input validation. You should add that.
Another problem I see is that in case the input is
create /dir/bar
you never initialize the string d but you still print it in main. That is undefined behaviour.
Try:
char d[50+1];
d[0] = '\0'; // Add this line
This is the code. It has to have the section before the void main() in it as it is the requirements i was told for the code.The stuff after void strcopy needs to be kept until void main().
#include <stdio.h>
void strcopy(char * string1, char * string2)
{
int i = 0;
while (string1[i] != '\0') {
string2[i] = string1[i];
i++;
}
return;
/* copies string1 to string 2 */
}
void main()
{
char string1[1000], string2[1000];
int i;
printf("Enter the string: \n");
scanf("%[^\n]s", string1);
printf(" %s ", string2);
return;
}
This is what is being printed and I'm stumped. Can someone help me out please?
Enter the string:
hello
t��\�
Thanks
First, you do not call strcopy, so you print just the uninitialized content of string2. Second, in strcopy, you forgot to terminate the target string (note that your loop terminates before the `\0' would be written). Write:
void strcopy(char * string1, char * string2)
{
int i = 0;
while (string1[i] != '\0') {
string2[i] = string1[i];
i++;
}
string2[i]='\0';
return;
/* copies string1 to string 2 */
}
If you do not terminate a string, then any bytes in the target memory are treated as "belonging to the string" until a 0x0 byte is reached. And these bytes might produce such weird output.
But you never called strcopy().
Add the function call after reading input:
strcopy(string1, string2);
Other issues are:
main() function should return int. So, change the definition to: int main(void) {... and return an int value such as return EXIT_SUCCESS;.
You haven't inserted the null byte into your destination. You need it because you are printing it as a string using %s. Add string2[i] = 0; after the while loop.
Remove the s from scanf()'s format specifier. %[^\n] is enough to read upto a newline. Instead you might considering using fgets(). Because scanf() as you use - is susceptible to buffer overflow and generally inferior.
I tried to get the inputs(strings) from user and store them in an array.But after I ran this code, the program instantly crashed.
#include <stdio.h>
int main() {
int i;
char *word[3];
for(i=0;i<3;i++)
{
printf(" Enter a word: ");
scanf("%s", &word[i]);
}
printf("%s ", word[0]);
return 0;
}
In this line:
scanf("%s", &word[i]);
You need to make sure word[i] is pointing somewhere, and has enough space to occupy the string entered. Since word[i] is a char * pointer, you need to at some time allocate memory for this. Otherwise, it is just a dangling pointer not pointing anywhere.
If you want to stick with scanf(), then you can allocate some space beforehand with malloc.
malloc() allocates requested memory on the heap, then returns a void* pointer at the end.
You can apply malloc() in your code like this:
size_t malloc_size = 100;
for (i = 0; i < 3; i++) {
word[i] = malloc(malloc_size * sizeof(char)); /* allocates 100 bytes */
printf("Enter word: ");
scanf("%99s", word[i]); /* Use %99s to avoid overflow */
/* No need to include & address, since word[i] is already a char* pointer */
}
Note: Must check return value of malloc(), because it can return NULL when unsuccessful.
Additionally, whenever you allocate memory with the use of malloc(), you must use free to deallocate requested memory at the end:
free(word[i]);
word[i] = NULL; /* safe to make sure pointer is no longer pointing anywhere */
Another approach without scanf
A more proper way to read strings should be with fgets.
char *fgets(char *str, int n, FILE *stream) reads a line from an input stream, and copies the bytes over to char *str, which must be given a size of n bytes as a threshold of space it can occupy.
Things to note about fgets:
Appends \n character at the end of buffer. Can be removed easily.
On error, returns NULL. If no characters are read, still returns NULL at the end.
Buffer must be statically declared with a given size n.
Reads specified stream. Either from stdin or FILE *.
Here is an example of how it can be used to read a line of input from stdin:
char buffer[100]; /* statically declared buffer */
printf("Enter a string: ");
fgets(buffer, 100, stdin); /* read line of input into buffer. Needs error checking */
Example code with comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMSTR 3
#define BUFFSIZE 100
int main(void) {
char *words[NUMSTR];
char buffer[BUFFSIZE];
size_t i, count = 0, slen; /* can replace size_t with int if you prefer */
/* loops only for three input strings */
for (i = 0; i < NUMSTR; i++) {
/* read input of one string, with error checking */
printf("Enter a word: ");
if (fgets(buffer, BUFFSIZE, stdin) == NULL) {
fprintf(stderr, "Error reading string into buffer.\n");
exit(EXIT_FAILURE);
}
/* removing newline from buffer, along with checking for overflow from buffer */
slen = strlen(buffer);
if (slen > 0) {
if (buffer[slen-1] == '\n') {
buffer[slen-1] = '\0';
} else {
printf("Exceeded buffer length of %d.\n", BUFFSIZE);
exit(EXIT_FAILURE);
}
}
/* checking if nothing was entered */
if (!*buffer) {
printf("No string entered.\n");
exit(EXIT_FAILURE);
}
/* allocate space for `words[i]` and null terminator */
words[count] = malloc(strlen(buffer)+1);
/* checking return of malloc, very good to do this */
if (!words[count]) {
printf("Cannot allocate memory for string.\n");
exit(EXIT_FAILURE);
}
/* if everything is fine, copy over into your array of pointers */
strcpy(words[count], buffer);
/* increment count, ready for next space in array */
count++;
}
/* reading input is finished, now time to print and free the strings */
printf("\nYour strings:\n");
for (i = 0; i < count; i++) {
printf("words[%zu] = %s\n", i, words[i]);
free(words[i]);
words[i] = NULL;
}
return 0;
}
Example input:
Enter a word: Hello
Enter a word: World
Enter a word: Woohoo
Output:
Your strings:
words[0] = Hello
words[1] = World
words[2] = Woohoo
There seems to be a bit of confusion in this area. Your primary problem is you are attempting to write each word to the address of each of pointers you declare with char *word[3];. (not to mention you have no storage allocated at the location pointed to by each pointer -- but you never get there as you attempt to write to the address of each pointer with &word[i] rather than to the pointer itself)
While you can use scanf you will quickly run into one of the many pitfalls with taking user input with scanf that plague all new C programmers (e.g. failing to handle the '\n' left in the input buffer, failing to handle whitespace in strings, failing to limit the number of characters read/written, failing to validate the read or handle EOF, etc...)
A better approach is to simply use fgets and then trim the '\n' that fgets read and includes in the buffer to which it stores the string. A simple example would be:
#include <stdio.h>
#include <string.h>
#define NWDS 3 /* declare a constant for the maximum number of words */
int main (void) {
int i, n = 0;
char word[NWDS][50] = { "" }; /* provide storage or allocate */
for (i = 0; i < NWDS; i++) { /* for a max of NWDS */
printf ("Enter word : "); /* prompt */
if (!fgets (word[i], sizeof word[i], stdin)) /* read/validate */
break; /* protect against EOF */
size_t len = strlen (word[i]); /* get length */
if (word[i][len-1] == '\n') /* check for trailing '\n' */
word[i][--len] = 0; /* overwrite with nulbyte */
}
n = i; /* store number of words read */
putchar ('\n'); /* make it pretty */
for (i = 0; i < n; i++) /* output each word read */
printf (" word[%d] : %s\n", i, word[i]);
#if (defined _WIN32 || defined _WIN64)
getchar(); /* keep terminal open until keypress if on windows */
#endif
return 0;
}
Go ahead and cancel input at any time by generating an EOF during input (ctrl + d on Linux or ctrl + z on windoze), you are covered.
Example Use/Output
$ ./bin/wordsread
Enter word : first word
Enter word : next word
Enter word : last word
word[0] : first word
word[1] : next word
word[2] : last word
Looks things over, consider the other answers, and let me know if you have further questions.
char *word[3]; // <-- this is an array of 3 dangling pointers, of type char*
// they still point nowhere, we later need to set them to some allocated location.
...
for(i=0;i<3;i++) {
word[i] = malloc(some_max_size * sizeof(char)); // <-- allocate space for your word
printf(" Enter a word: ");
scanf("%s", word[i]); // <-- not &word[i]; word[i] is already a char* pointer
}
You are declaring word as array of pointer (char *word[3];). You have to allocate memory to store data. Allocate memory with malloc or similar functions before assigning values.
Yes the code crashes because declaring an array of character
pointers is not enough, you need to set the pointers to point
to memory where the strings can be stored.
E.g.
const int maxLen = 32;
char* word[3] = {NULL,NULL,NULL};
word[i] = malloc(maxLen);
then read the string from keyboard, to ensure that the string is not too
long use fgets and maxLen:
printf("Enter a word:");
fgets(word[i],maxLen,stdin);
#include <stdio.h>
int main(){
int n;
int i=0;
scanf("%d",&n);
char arr[n];
while(n>i){
scanf("%s",&arr[i]);
i+=1;
}
while(n-i<n){
printf(" %c ",arr[n-i]);
i-=1;
}
}
The code char *word[3] made a 3-element array of pointers!
See, you have basically created a character array of pointers, so you cannot put a "string" into each one of them, because the type of a pointer variable is long hexadecimal.
The condition is:
I want to input a line from standard input, and I don't know the size of it, maybe very long.
method like scanf, getsneed to know the max length you may input, so that your input size is less than your buffer size.
So Is there any good ways to handle it?
Answer must be only in C, not C++, so c++ string is not what I want. I want is C standard string, something like char* and end with '\0'.
The C standard doesn't define such a function, but POSIX does.
The getline function, documented here (or by typing man getline if you're on a UNIX-like system) does what you're asking for.
It may not be available on non-POSIX systems (such as MS Windows).
A small program that demonstrates its usage:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *line = NULL;
size_t n = 0;
ssize_t result = getline(&line, &n, stdin);
printf("result = %zd, n = %zu, line = \"%s\"\n", result, n, line);
free(line);
}
As with fgets, the '\n' newline character is left in the array.
One way is to run a loop with getchar and keep placing the characters into an array. Once the array is full, reallocate it to a larger size.
There is an often overlooked conversion specification within scanf that will allocate memory sufficient to hold the string input regardless of length. Newer versions of scanf use m for this purpose. Older versions used a. For example:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *str = NULL;
printf (" enter a string of any length, whitespace is OK: ");
scanf ("%m[^\n]%*c", &str);
printf ("\n str: %s\n\n", str);
if (str) free (str);
return 0;
}
Note: scanf requires a char ** pointer argument to receive the allocated string. Also note scanf does not include the '\n' in the stored string. Further note the %*c which receives and discards the '\n' character to prevent the newline from remaining in the input buffer. You may also precede the conversion specifier with whitespace to skip any/all whitepace that may exist in the input buffer.
Lastly Note: there are reports that not all implementations of scanf offer this feature. (which may also be confusion of the m/a change) Check your implementation.
One of the method is using getchar() function we can get input in a character and transfer it to dynamicall created array. You can see that when it exceeds the default length set by us, we reallocated space for storing character
#include<stdio.h>
#include<stdlib.h>
void main(){
int size = 10;
char* str;
str = (char*) calloc(size,sizeof(char));
char c;
c = getchar();
int t = 0;
int cnt = 0;
int len;
while(c!='\n') {
if(cnt > size) {
str = (char*) realloc(str,2*cnt);
}
str[t] = c;
c = getchar();
t++;
cnt++;
}
str[t]='\0';
printf("The string is %s\n",str);
len = strlen(str);
printf("The size is %d",len);
}
use getchar, malloc and realloc for reading the unlimited input string
Declare String type, you can also use char *
// String type
typedef char *String;
I write this function for joining the char in the end of string
/**
* Join the Char into end of String
*
* #param string - String
* #param c - joined char
*/
void String_joinChar(String *string, const char c)
{
const size_t length = strlen(*string);
(*string) = (String)realloc((*string), sizeof(char) * (length + 2));
(*string)[length] = c;
(*string)[length + 1] = '\0';
}
This function for inputting string, which read the char from keyboard by using getchar and join it in the end of current string.
/**
* Input String
*
* #return Inputed String
*/
String String_input()
{
String string = (String)malloc(sizeof(char));
strcpy(string, "");
char cursor;
fflush(stdin);
while ((cursor = getchar()) != '\n' && cursor != EOF)
{
String_joinChar(&string, cursor);
}
return string;
}
Cause of using char *, malloc and realloc, we must free it
/**
* Destroy String
*
* #param string - Destroyed String
*/
void String_destroy(String string)
{
free(string);
}
And now we just use it !!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
String string = String_input();
printf("\n%s\n", string);
String_destroy(string);
return 0;
}
Hope useful to you!