Finding substrings inside strings inputted by the user - c

I'm trying to write down a substring finder that acts like the fowl language blockers in chats. For some reason the code crashes every time I run it.
int main ()
{
char *sent;
char *key1 = "WORD";
printf("Input: \n");
sent = scanf("%d");
if(strstr(sent, key1) != NULL) {
printf("YES");
}
}

You did not allocate memory for sent. When you write char *sent, the pointer is pointing to some uninitialized memory at an unknown address. When you read it in, it must have enough space to hold the input--scanf will not allocate memory for you. This is the revised code
int main()
{
char sent[16]; /* alloced 16 chars, including '\0' */
char *key1 = "WORD";
printf("Input: \n");
scanf("%s", sent);
if (strstr(sent, key1) != NULL)
printf("YES");
return 0;
}
You also used scanf wrong. The %d specifier reads decimal integers, not strings. For a string, you will need %s. And scanf doesn't return the read value. It returns a failure/succeeded signal. you need to pass the address into the variable argument list.
A final note: If you are reading sentences, scanf will not suffice. You will need fgets:
char buf[80];
fgets(buf, 80, stdin);
buf will then contain the first 80 characters from the standard input.

Related

Problem calling a function that uses strtok() inside of a while loop

Hi i'm struggling with understanding what's wrong with my program.
My best guess is something related with this line of code here:
scanf("%s", str);
The thing is i'm trying to call a function that uses a strtok on a String passed on to it typed by the user, all of this inside of a while loop as shown in the code example below:
int i = 0;
char str[80];
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result (not what i want, see further below what i actually want):
Type in some string so i can break it: hey there how are you doing!
hey
Loop 0 ended.
Type in some string so i can break it:
there
Loop 1 ended.
Type in some string so i can break it:
how
Loop 2 ended.
The reason why i think this is caused by the scanf line is because the program works fine when i'm using instead some dummy pre-declared String
int i = 0;
while(i != 3){
char str[80] = "hey there how are you doing!";
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
return 1;
Result:
hey
there
how
are
you
doing!
Loop 0 ended.
hey
there
how
are
you
doing!
Loop 1 ended.
hey
there
how
are
you
doing!
Loop 2 ended.
Here's the funtion that uses strtok, most of the code here is taken from https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm
int testFunc(char linha[80]){
//
const char s[2] = " ";
char *token;
/* get the first token */
token = strtok(linha, s);
/* walk through other tokens */
while(token != NULL) {
printf("%s\n", token);
token = strtok(NULL, s);
}
return 1;
}
I'm puzzled, it's like the program is executing testFunc() in paralel with the main function.
I think the problem is when you execute this loop:
while(i != 3){
printf("Type in some string so i can break it: ");
scanf("%s", str);
testFunc(str);
printf("Loop %i ended.\n", i);
i++;
}
scanf gets only one word at a time, so the loop cycles 3 times, you only get 3 words no matter how long the input string is.
On the other hand, in your other example you already have a string to break apart so the function will work.
There are different ways to get spaced strings from the console but here is what I consider to be a good option to do it:
str[MAX_SIZE];
fgets(str, MAX_SIZE, stdin);
// where MAX_SIZE is the maximum size you want to allow for the string,
//must be smaller than str.
According to scanf(3) man page:
Matches a sequence of non-white-space characters; the next
pointer must be a pointer to the initial element of a
character array that is long enough to hold the input sequence
and the terminating null byte ('\0'), which is added
automatically. The input string stops at white space or at
the maximum field width, whichever occurs first
You can use fgets or fread for input:
char buffer[1000];
/* fgets (reads a line of text with trailing newline */
fgets (buffer, 1000, stdin);

How to input strings into an array in C?

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.

Beginner in C: strings and memory

So this course I'm doing wants us to play around with memory management and pointers. I'm not really fully understanding them.
I keep getting a error:
Segmentation fault (Core dumped)
Apparently I don't have access to memory?
It's something wrong in my slen function?
/*
In these exercises, you will need to write a series of C functions. Where possible, these functions should be reusable (not use global variables or fixed sized buffers) and robust (they should not behave badly under bad input eg empty, null pointers) .
As well as writing the functions themselves, you must write small programs to test those functions.
- Remember, in C, strings are sequences of characters stored in arrays AND the character sequence is delimited with '\0' (character value 0).
----------------------------------------------------
1) int slen(const char* str)
which returns the length of string str [slen must not call strlen - directly or indirectly]
*/
#include <stdio.h>
#include <stdlib.h>
/* Returns the length of a given string */
int slen(const char* str) {
int size = 0;
while(str[size] != '\0') {
size++;
}
return size;
}
/*
2) char* copystring(const char* str)
which returns a copy of the string str. [copystring must not call any variant of strcpy or strdup - directly or indirectly]*/
char* copystring(const char* str) {
int size = slen(str);
char *copy = (char*) malloc (sizeof(char) * (size + 1));
copy[size] = '\0';
printf("before loop");
int i = 0;
while (*str != '0') {
copy[i++] = *str++;
}
return copy;
}
int main() {
char *msg = NULL;
printf("Enter a string: ");
scanf("%s", &msg);
int size = slen(msg);
//printf("The length of this message is %d.", size);
// printf("Duplicate is %s.", copystring(msg));
// Reading from file
}
The problem isn't in your slen function, it happens before that when you're using scanf:
you need to make some space for the string that you're reading from the user using scanf
you don't need to pass the address of your memory buffer to scanf, the variable is already holding an address.
Amended code:
char msg[101];
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
Alternately, if you're being asked to learn about memory allocation, study the usage of malloc:
char *msg = malloc(101);
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
While learning about malloc, don't forget to also study up on the associated usage of free.
Also important and significant here is the management of your buffer size: when you make memory for the string that you'll be scanning from the user, you should put a limit on the amount of string that you actually read. There are a few ways to do this: start by studying the scanf format string, where you can use:
scanf("%100s", msg);
You need to assign memory to msg in your main
Either use char msg[10] or use malloc.
char *msg = malloc(10*sizeof(char))

fgets give me random big number

This is my code, I don't know how to use fgets after scanf so I am using fgets in the 26th line too but every time I use it, it give me big number(ex.2752100) but I write 2.
Why is it doing it?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
char veta[100];
int line = 1;//tell what line it is on
int found = 0;
char a[100];//put the characters of the line into here
char b[100];
char linesearch[10];//the line you are looking for
FILE *file;//the file pointer
file = fopen("text.txt","r");//point the file
if (file == NULL)
{
printf("file does not exist or doesn't work\n");
return 0;
}
printf("Ahoj, naucim te psat snadno a rychle! \n");
printf("Vyber si uroven slozitosti od 1 do 10:\n");
//scanf("%d", &linesearch);
fgets(linesearch,10,stdin);
printf("\nHledam uroven %d ...\n\n",linesearch);
EDIT:
i have another problem:
while(fgets(a,100,file))
{
if(x == line)
{
found = 1;
printf("level %d found,level %d say: %s",x,x,a);
}
else
printf("reading level: %d\n",line );
line++;
}
printf("\nwrite your string as fast as you can!!");
fgets(veta,40,stdin);
if (strcmp(veta,a) == 0)
{
printf("\nwell done!!!!\n");
}
else
{
printf("\nwrong!!!!\n");
printf("%s", a);
printf("%s", veta);
}
i have small senteces(ex I like my mum and she likes me,etc) i want to compare my text with text from file and get answer if I write it well or not. Bonus points if it tell me how many mistakes i did it will be powerful!.
The fgets() function reads character data from the input. To convert this character data to an integer, use atoi() or a similar function.
fgets(linesearch, 10, stdin);
int x = atoi(linesearch);
printf("\nHledam uroven %d ...\n\n",x);
Your printf statement is printing out the address of the linesearch array, which will seem like a random big number.
If you want to read from stdin, into a char array, using scanf() and then print as an int:
scanf("%s", linesearch); // e.g. reads 1234 into array linesearch[].
printf(" %s ...\n\n",linesearch); // Prints string in array linesearch[].
printf(" %p ...\n\n",linesearch); // Prints base address of linesearch[].
int iNum = atoi(linesearch); // Converts string "1234" to number 1234.
printf(" %d ...\n\n",iNum); // Prints the converted int.
iNum++; // Can perform arithmetic on this converted int.
You are getting a big number from printf because you used %d in the format. The number is the memory address of your character array. To print the character array, update the format to %s.

Dynamically prompt for string without knowing string size

In C, what is the best way of prompting and storing a string without wasted space if we cannot prompt for the string length. For example, normally I would do something like the following...
char fname[30];
char lname[30];
printf("Type first name:\n");
scanf("%s", fname);
printf("Type last name:\n");
scanf("%s", lname);
printf("Your name is: %s %s\n", fname, lname);
However, I'm annoyed with the fact that I have to use more space than needed so I do not want to use char fname[30], but instead dynamically allocate the size of the string. Any thoughts?
You can create a function that dynamically allocates memory for the input as the user types, using getchar() to read one character at a time.
#include <stdio.h>
#include <stdlib.h>
void* safeRealloc(void* ptr, size_t size) {
void *newPtr = realloc(ptr, size);
if (newPtr == NULL) { // if out of memory
free(ptr); // the memory block at ptr is not deallocated by realloc
}
return newPtr;
}
char* allocFromStdin(void) {
int size = 32; // initial str size to store input
char* str = malloc(size*sizeof(char));
if (str == NULL) {
return NULL; // out of memory
}
char c = '\0';
int i = 0;
do {
c = getchar();
if (c == '\r' || c == '\n') {
c = '\0'; // end str if user hits <enter>
}
if (i == size) {
size *= 2; // duplicate str size
str = safeRealloc(str, size*sizeof(char)); // and reallocate it
if (str == NULL) {
return NULL; // out of memory
}
}
str[i++] = c;
} while (c != '\0');
str = safeRealloc(str, i); // trim memory to the str content size
return str;
}
int main(void) {
puts("Type first name:\n");
char* fname = allocFromStdin();
puts("Type last name:\n");
char* lname = allocFromStdin();
printf("Your name is: %s %s\n", fname, lname);
free(fname); // free memory afterwards
free(lname); // for both pointers
return 0;
}
From man scanf:
• An optional 'm' character. This is used with string conversions (%s,
%c, %[), and relieves the caller of the need to allocate a
corresponding buffer to hold the input: instead, scanf() allocates a
buffer of sufficient size, and assigns the address of this buffer to
the corresponding pointer argument, which should be a pointer to a
char * variable (this variable does not need to be initialized before
the call). The caller should subsequently free(3) this buffer when it
is no longer required.
this however is a POSIX extension (as noted by fiddling_bits).
To be portable I think that in your usage case I would prepare a function like the following:
char *alloc_answer() {
char buf[1000];
fgets(buf,sizeof(buf),stdin);
size_t l = strlen(buf);
if (buf[l-1]=='\n') buf[l]=0; // remove possible trailing '\n'
return strdup(buf);
}
even if this solution will break lines longer than 1000 characters (but it prevents buffer overflow, at least).
A fully featured solution would need to read input in chunks and realloc the buffer on every chunk...

Resources