The goal is to count all the vowels from a char* the user puts in. The program has other functions and this is called from main.
I have also included stdio.h, stdbool.h, and string.h
char* countWord;
int vowels;
printf("Type the word to count vowels:");
scanf("%s", &countWord);
vowels = vowelCount(countWord);
printf("%d", vowels);
The following is the function I was used. I also tried strlen(string) which caused a crash as well.
int vowelCount(char* string){
int vowels;
int i;
int size;
printf("function entered");
for (; *string; string++){
if (string[i] == 'a'){
vowels++;
} else if(string[i] == 'e'){
vowels++;
} else if(string[i] == 'i'){
vowels++;
} else if(string[i] == 'o'){
vowels++;
} else if(string[i] == 'u'){
vowels++;
}
}
return vowels;
}
What am I doing wrong? I'm new to C but have experience in other languages.
Thanks in advance.
Exercising undefined behavior...
You have not allocated any space for the pointer to point at, so when you're trying to use it, the behavior is undefined.
Simply make some space for it:
char buffer[1000];
char* countWord = buffer;
and there's another mistake:
scanf("%s", &countWord);
^
You shouldn't use an address of (&) operator here. Just drop it. You're reading a string into the target of the pointer, not the pointer itself.
Also note that you're doing some mixed code in your function. You're using an uninitialized variable i, yet that seems unnecessary since you're incrementing the pointer string. So you want to drop i and change the if statement to
if (*string == 'a')
And be sure to initialize vowel as well:
int vowel = 0;
From the scanf man page, the format specifier %s:
"Matches a sequence of non-white-space characters; the next pointer must be a pointer to char, and the array must be large enough to accept all the sequence and the terminating NUL character."
The pointer your code provides matching the sole %s specifier, however, is the address of the variable declared as a pointer to char: &countWord is of type pointer to pointer to char. Thus, scanf writes (or attempts to write) the matched sequence to a location sized for a pointer to char, not necessarily the sequence length + null terminator. This may thus write into unallocated memory, which is undefined behavior (and oftentimes, a segfault). Simply removing the address-of operator will not suffice on its own to resolve the issue, either, because simply declaring a pointer to char does not allocate the space for the characters you presumably want said pointer to point to at some point.
What you must do to read a string using scanf as you have attempted to is to ensure that sufficient space is allocated to store the sequence you will read, then pass scanf a pointer to that space. These could be allocated statically:
char countWord[512]; // Assumes input sequence will consist of no more than 511 characters, since space is needed for the terminating NUL character
Or dynamically:
char* countWord = malloc(sizeof(char) * 512); // Same size as the above, so input still must be no more than 511 characters, but dynamically allocated so will need to be explicitly freed later to avoid leaking memory
Given the space is allocated and sufficient, you can then pass countWord (which defined in either of the manners shown above, is effectively a pointer to char, no address-of required*)
If the sequence your scanf call is reading as input is under some defined input restriction, you can pass scanf a pointer to sufficient allocated space for the maximum allowable input sequence size, guaranteeing the read sequence will not exceed the allocated space.
This, however, depends on the input following said limits. Better would be for your code to limit how much it might read, so it really is guaranteed that you won't access unallocated memory, even if your input source decides not to behave as expected. scanf provides a mechanism to do this by including a field width with the specifier, e.g.:
scanf("%511s", countWord); // Reads at most 511 bytes of input into the location pointed to by countWord, plus the NUL terminator.
Obviously, instead of 511 characters of input you would choose a suitable number that all valid inputs to the program should fall within.
The other answer noting that variables should be initialized before being read from is also true, but crashes specifically are more likely to result from interacting with unallocated memory than allocated but merely uninitialized memory (not that reading from the latter isn't undefined behavior).
*Technically there are some differences between a char array declared explicitly as an array and a pointer to char, but those differences are not particularly relevant to this question.
Your lack of memory allocation for countWord was already mentioned in other answers.
But you also have a problem with usage of uninitialized variable while counting the vowels.
You iterate using string pointer and add some random value i on top of that.
int vowelCount(char* string){
int i; // <<=== not initialized, holding ramdon garbage value
for (; *string; string++){
if (string[i] == 'a'){ // << adding random index to pointer.
...
Related
I am confused about how pointers to characters work. when I run the following code, what happens?
int main()
{
char* word;
scanf("%s",word);
printf("%s",word;
}
the first line in the main is defining a pointer to char without initialization. scanf should store the word somewhere and give the address to the pointer, right? what if I input a big string, would it overwrite something in the memory?
And what happens in the first line in the following code other than defining a pointer to char. Does the compiler set some limits? or I can't exceed the size specified, right? If done, I will have a run time error, right? what is the difference between the two cases?
int main()
{
char word[100];
scanf("%s",word);
printf("%s",word;
}
What about pointers to other types? Can I just keep writing to the following places using offsets?
scanf should store the word somewhere and give the address to the pointer, right?
No. It is the other way around. You define the address where scanf shall store the value. As you fail to initialize the pointer to some valid address, you cause undefined behaviour that might result in a crash in best case or seem to work in worst case.
And what happens in the first line in the following code other than defining a pointer to char.
There is no pointer involved at all. An array is not a pointer. An array provides all the memory it needs to store all its members. A pointer doesn't do this.
Does the compiler set some limits? or I can't exceed the size specified, right?
You can write wherever you want. No one will prevent you from doing this. At least no from trying. If you write to some location that does not belong to the memory you allocated, you again cause undefined behaviour.
The function scanf requires that you pass it the address of a sufficiently large memory buffer for storing the string. If you don't do this, then you will be invoking undefined behavior (i.e. your program may crash).
Simply passing a wild pointer (i.e. an arbitrary memory address) is not sufficient. Rather, you must reserve the memory that you intend to use, for example by declaring an array or by using the function malloc.
Using the %s scanf conversion format specifier by itself is not a good idea, because even if the allocated memory buffer has a size of 100 characters, if the user types more than 99 characters (100 including the terminating null character), then the function will write to the array out of bounds, causing undefined behavior. Therefore, you should always limit the number of characters that are written, in this case by writing %99s instead of simply %s.
Also, before using the result of scanf, you should always check the return value of the function, and only use the result if the function was successful.
int main()
{
char word[100];
if ( scanf( "%99s", word ) == 1 )
printf( "%s\n", word );
else
printf( "input error!\n" );
}
what if I input a big string, would it overwrite something in the memory?
It doesn't have to be a "big" string. Writing even a "small" string to a wild pointer will cause undefined behavior and something important may be overwritten, or your program may crash.
And what happens in the first line in the following code other than defining a pointer to char. Does the compiler set some limits?
The line
char word[100];
will allocate an array of 100 characters, i.e. it will give you a memory buffer that is sufficiently large to store 100 characters. This does not give you a pointer. However, when using the array word in the line
scanf("%s",word);
the array word will decay to a pointer to the first element.
Does the compiler set some limits? or I can't exceed the size specified, right?
The compiler won't prevent you from writing to the array out of bounds, but if you allow this to happen, then your program will have undefined behavior (i.e. your program may crash). Therefore, you probably don't want to allow that to happen.
If done, I will have a run time error, right?
If you are lucky, then yes, your program will crash immediately and you will easily be able to identify and fix the bug. If you are unlucky, then no, your program won't crash, but will work as intended, and you won't notice the bug for a very long time, until much later in development, when one day the bug starts overwriting something important in your program. In that case, the bug will probably be hard to diagnose.
This is because C is not a memory-safe language.
However, because these kinds of bugs are often hard to find, there are tools which can help detect these kinds of bugs, such as valgrind and AddressSanitizer.
According to the description of the conversion specifier %s in the C Standard
If no l length modifier is present, the corresponding argument shall
be a pointer to the initial element of a character array large enough
to accept the sequence and a terminating null character, which will be
added automatically.
That is when you pass a pointer as an argument of the function that corresponds to the format %s it shall point to the first element of a character array where the input string will be stored. The character array shall be large enough to accommodate the entered string (including the appended terminating zero character '\0')
In the first program
int main()
{
char* word;
scanf("%s",word);
printf("%s",word;
}
the pointer word is uninitialized and has an indeterminate value. So these two statements
scanf("%s",word);
printf("%s",word;
invoke undefined behavior.
You need to provide a valid value of the pointer that will point to a character array. For example
char s[100];
char *word = s;
Or you can allocate memory dynamically like
char *word = malloc( 100 * sizeof( char ) );
In the second program
int main()
{
char word[100];
scanf("%s",word);
printf("%s",word;
}
the array word used as an argument is implicitly converted to a pointer to its first element. If you will enter a string that fits in the array with 100 elements then the program will behave correctly.
However if you will enter 100 or more characters without embedded spaces then the program again will have undefined behavior.
To avoid such a situation you can specify the maximum length of the string that can be read in the array word by using the length modifier the following way
scanf("%99s",word);
If you want to input a string that may have embedded spaces you should use another conversion specifier. For example
scanf("%99[^\n]", word );
or
scanf(" %99[^\n]", word );
Here are two demonstration programs that show the difference between the two conversion specifiers used to enter a string.
#include <stdio.h>
int main(void)
{
char word[100];
scanf( "%99s", word );
puts( word );
return 0;
}
If to enter the string
Hello Mohammed Elbagoury
then the program output will be
Hello
And the second program
#include <stdio.h>
int main(void)
{
char word[100];
scanf( "%99[^\n]", word );
puts( word );
return 0;
}
Again if to enter
Hello Mohammed Elbagoury
then the program output will be
Hello Mohammed Elbagoury
If you will enter more than 99 characters then only the first 99 characters will be stored in the array appended with the terminating zero character '\0'.
As for your this question
Can I just keep writing to the following places using offsets?
then you can use the pointer arithmetic to store data in any position of an array. for example
int a[10];
scanf( "%d", a + 5 );
In this case a number will be written in the element of the array a[5].
The above statement is equivalent to
scanf( "%d", &a[5] );
Say, in main(); you read a string from a file, and scan it into a statically declared char array. You then create a dynamically allocated char array with with length strlen(string).
Ex:
FILE *ifp;
char array_static[buffersize];
char *array;
fscanf(ifp, "%s", array_static);
array = malloc(sizeof(char) * strlen(array_static) + 1);
strcpy(array_static, array);
Is there anything we can do with the statically allocated array after copying it into the dynamically allocated array, or will it just be left to rot away in memory? If this is the case, should you even go through the trouble of creating an array with malloc?
This is just a hypothetical question, but what is the best solution here with memory optimization in mind?
Here's how to make your life easier:
/* Returns a word (delimited with whitespace) into a dynamically
* allocated string, which is returned. Caller is responsible
* for freeing the returned string when it is no longer needed.
* On EOF or a read error, returns NULL.
*/
char* read_a_word(FILE* ifp) {
char* word;
/* Note the m. It's explained below. */
if (fscanf(ifp, "%ms", &word) != 1)
return NULL;
return word;
}
The m qualifier in the scanf format means:
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.
It's a Posix extension to the standard C library and is therefore required by any implementation which hopes to be Posix compatible, such as Linux, FreeBSD, or MacOS (but, unfortunately, not Windows). So as long as you're using one of those platforms, it's good.
I am actually supposed to dynamically store a string. I have tried the below,
It is printing everything but it terminating as soon as a space is included in my input. can someone explain is why?
Also what is the right way to do it :
int i;
char *a;
a=(char *)malloc(sizeof(char));
scanf("%s",a);
for(i=0;*(arr+i)!='\0';i++)
printf("%c",*(arr+i));
It is printing everything but it terminating ...
Consider your memory allocation statements:
char *a;
a=(char *)malloc(sizeof(char));
By allocating only sizeof(char) bytes to the buffer a, then attempting to write anything more than the null terminator to it, you are invoking undefined behavior. (Note: sizeof(char) in C is by definition equal to 1, always)
C strings are defined as a null terminated character array. You have allocated only one byte. The only legal C string possible is one containing only the null termination byte. But your code attempts to write much more, and in so doing encroaches on memory locations not owned by your process. So in general, when creating strings, follow two simple rules:
Determine max length of string you need
allocate memory to max length + 1 bytes to accommodate termination byte.
Example if max string is x characters long, create the memory for x + 1 characters:
char inputStr[] = {"This string is x char long"};
char string = malloc(strlen(inputStr) +1); //+1 for null byte
strcpy(string, inputStr);
Note, in C it is not recommended to cast the return of malloc() and family.
You've two problems with your code. Firstly, you only allocate enough space for 1 character and since strings have to be NUL terminated, the longest string you could have is 0 characters long. Since you don't know how long the text you're going to read in, you could start with an arbitrary size (say 1024).
a=malloc(1024);
Secondly, scanf will only read up to the next space when you use "%s". It also isn't constrained by the available space in a. A better way to to read in an entire line of text, is to use fgets like this
fgets(a,1024,stdin);
This will read up to 1023 characters or up to and including the next newline character. It will NUL terminate the string for you as well.
You can then print it as a string.
printf("%s",a);
char *a;
/* Initial memory allocation */
a = (char *) malloc(1024); // your buffer size is 1024
// do something with a
free(a);
Copy bellow string in your variable then print the string with "%s" as string and theres no need use of "%c" :
strcpy(a, "this is a string");
printf("String = %s", a);
Dont forget using of free(), if you dont use of this then you will get memory leak problem.
gcc compiles perfectly well, but as soon as scanf accepts a string it seg faults. I'm sort of at a loss. Here's the code.
char *line[256];
void *mainThread()
{
while (*line != "quit") {
scanf("%s", *line);
printf("%s", *line);
}
return;
}
Is there something about scanf I'm not understanding here?
First, you are allocating an array of pointers to characters, not an array of char:
char *line[256]; /* allocates 256 pointers to a character -
(pointers are initialized to NULL) */
You need to allocate an array of characters instead:
char line[256]; /* allocates 256 characters */
Second, you need to use strcmp to compare the strings - with !=, you are comparing the pointer (address) stored in line[0] (which is the same as *line) with a pointer to the string literal "quit", and they are always different.
You can use the following sscce as a starting point:
#include <string.h>
#include <stdio.h>
char line[256];
int main()
{
while (strcmp(line, "quit") != 0) {
scanf("%s", line);
printf("%s", line);
}
return 0;
}
Some additional notes:
See #Joachims answer for an explanation of the actual cause of the segmentation fault.
You are declaring your function to return a void* pointer, but you are not returning anything (using return with no argument). You should then simply declare it as void.
Do not use scanf() to read input, since it might read more characters than you have allocated which leads to buffer overflows. Use fgets() instead. See also Disadvantages of scanf.
Always compile with all warnings enabled, and take them serious - e.g. if you are using gcc, compile with -Wall -pedantic.
When declaring global variables, they are initialized to zero. And as you are declaring an array of pointers to char (instead of an array of char as I think you really intended) you have an array of 256 NULL pointers.
Using the dereference operator * on an array is the same as doing e.g. array[0], which means that as argument to both scanf and printf you are passing line[0], which as explained above, is a NULL pointer. Dereferencing NULL pointers, like scanf and printf will do, is a case of undefined behavior, one that almost always leads to a crash.
It is compiling because your program is syntactically correct. However, it has serious semantic errors which show up as program crash due to segfault. The global array line is initialized to zero, as any global variable. Since, line is an array of pointers (not an array of characters which is intended), the zeros are interpreted as NULL, the null pointer. *line is same as line[0] and the string literal "quit" evaluates to a pointer to its first element. Therefore the while condition is the same as
while(NULL != "quit") // always true
Next, scanf("%s", *line); tries to write the input string into the buffer pointed to by line[0] which is NULL - a value which is unequal to the address of any memory location. This will result in segfault and cause the program to crash.
There are other mistakes in your code snippet. Let's take them one by one.
char *line[256];
The above statement defines an array line of 256 pointers to characters, i.e., its type is char *[256]. What you need is an array of characters -
char line[256];
You can't compare array in C. What you can do is compare them element-by-element. For strings, you should use the standard library function strcmp. Also, please note that the %s conversion specifier in the format string of scanf reads a string from stdin and writes it into the buffer pointed to by the next argument. It puts a terminating null byte at the end but it does not check for buffer overrun if you input a string too large for the buffer to hold. This would lead to undefined behaviour and most likely segfault due to illegal memory access. You should guard against buffer overrun by specifying maximum field width in the format string.
void *mainThread();
The above function declaration means that mainThread is function which returns a pointer of void * type and take an unspecified but fixed number and type of arguments because empty parentheses mean no information about the parameter list is provided. You should write void in the parameter list to mean that the function takes no arguments. Also note that the empty return statement in your function would cause undefined behaviour if the return value of the function is used because you are not returning anything and would be using the garbage value in the return address of the function instead. Assuming that you want to return the string, it should be defined as -
char line[256];
char *mainThread(void) {
while(strcmp(line, "quit") != 0) {
scanf("%255s", line); // -1 for the terminating null byte
printf("%s", line);
}
return line;
}
char *str;
printf("Enter string:\n");
scanf("%s",str);
OUTPUT:
runtime-check failure#3
str is being used without being initialized
Allocate an array and read into that:
char str[100];
if (scanf("%99s", str) != 1)
...error...
Or, if you need a pointer, then:
char data[100];
char *str = data;
if (scanf("%99s", str) != 1)
...error...
Note the use of a length to prevent buffer overflow. Note that the length specified to scanf() et al is one less than the total length (an oddity based on ancient precedent; most code includes the null byte in the specified length — see fgets(), for example).
Remember that %s will skip past leading white space and then stop on the first white space after some non-white space character. In particular, it will leave the newline in the input stream, ready for the next input operation to read. If you want the whole line of input, then you should probably use fgets() and sscanf() rather than raw scanf() — in fact, very often you should use fgets() and sscanf() rather than scanf() or fscanf(), if only because it make sensible error reporting a lot easier.
Its an undefined behavior if you dont initialize it.You have an uninitialized pointer which is reading data into memory location which may eventually cause trouble for you. You've declared str as a pointer, but you haven't given it a valid location to point to; it initially contains some random value that may or may not be a writable memory address.Try to allocate memory to the char *str;
char *str = malloc(sizeof(char)*100);
char *str declares str as a pointer to char type. scanf("%s",str) will read only E from the entered string.
You might NOT want to use exactly scanf("%s") (or get in the habit of using it) as it is vulnerable to buffer overflow (i.e. might accept more characters than your buffer can hold). For a discussion on this see Disadvantages of scanf
You have to allocate memory before assigning some value to a pointer. Always remember that pointer points to a memory location and you have to tell him what memory location you want to assign for him. So, for doing that you have to do :
str = (char*)malloc(sizeof(char));
This will assign you 1byte of memory block. So, you can assign only one character in this memory block. For a string you have to assign as many blocks depending on the number of characters in the string.Say, "Stack" requires 5 character and 1 extra block for '\0'. So, you have to assign at least 6 memory block to him.
str = (char*)malloc(6*sizeof(char));
I hope this will help you to grow more concepts in C.