#include <stdio.h>
#include <unistd.h>
int main(void)
{
int n_of_words = 0;
#define MAX_STR_SZ 256
// asking for user input
char string[50];
printf("\nPlease input a string of text.\n\n");
fgets(string, MAX_STR_SZ, stdin);
char * words[n_of_words];
// extracting the first word
words[n_of_words] = strtok(string, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
// looping through the string to extract all other words
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
sleep(10);
return 0;
}
I'm very new to programming, but I was trying to write a function to extract words from a user inputted string and save them in an array for later use in the program. I added the 2 printf lines of code to see if it was working properly. I always get a segmentation fault error after the second iteration of the while loop. Also, somehow this problem didn't present itself when I compiled the same code on the CS50 ide (Cloud9), but it happens in any other case.
Few issues which can be resolved to prevent segmenatation fault
:
string.h
header in the source code for strtok
function #include <stdio.h> #include <unistd.h>
#define MAX_STR_SZ 256
char string
array is of length 50
but the fgets
is allowing 256
and can lead to bufferoverflow. char string[50]; printf("\nPlease input a string of text.\n\n"); fgets(string, MAX_STR_SZ, stdin);
n_of_words
is 0
. So, the declaration
char * words[n_of_words];
Will not create an array of the desired length.
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
You are accessing a memory location which was never declared,
n_of_words ++; words[n_of_words] = strtok(NULL, " "); //words[1] or any index was never declared.
Every C program gets for free a list of the command line parameters, in general declared as int main(int argc, char* argv[]);
or int main(int argc, char** argv);
This is precisely what you are trying to replicate with int n_of_words
and char* words[n_of_words];
But you are doing it the wrong way.
A first note on this 3 lines from your code:
#define MAX_STR_SZ 256
char string[50];
fgets(string, MAX_STR_SZ, stdin);
You are setting 256 as the limit for fgets()
to read, but you have only 50 chars in string. Many times it will work in this case, since you are reading from the keyboard and many of us would not key more than a few words in, but you have a problem. Change the limits.
strtok()
is probably not the best one to choose here. A single loop using scanf()
could read many lines and break all of then in words skipping over the newlines and such, and you may find it easier to code.
Anyway, back to your code: since you do not know in advance the number of words, you can estimate a limit or allocate memory for the strings one by one, or even in blocks. But
you need to allocate memory for the strings you will have a SegFault at the moment you try to write in the
words[]
array.
I changed a minimum of your code so you can see an example, and I fixed the number of strings in a #define
similar of what you have written so far.
A simple way to go is declare --- as C does in main()
--- words[]
as char**
and allocate memory for them as soon as you know you have at least one string to record.
But then you need to note that you will have just the pointers. They are still pointing to nothing.
As soon as you have a string to load you need to allocate memory for it, plus 1 byte for the terminating '\0'
, and then copying the string and saving the address in the corresponding pointer in the words[]
array.
See the code.
#define MAX_STR_SZ 256
#define MAX_N_OF_STRINGS 30
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// https://stackoverflow.com/questions/63343800/
// c-program-segfaulting-with-strtok
int main(int argc, char** argv)
{
int n_of_words = 0;
int max_n_of_words = MAX_N_OF_STRINGS;
char** words;
// asking for user input
char string[MAX_STR_SZ];
printf("\nPlease input a string of text: ");
fgets(string, MAX_STR_SZ, stdin);
string[strlen(string) - 1] = 0; // drops the final '\n'
printf("full string was '%s'\n", string);
if (strlen(string) == 0) return -1; // no input
// we have at least one byte
// before anything build words[]
words = (char**)malloc(max_n_of_words * sizeof(char*));
// now words[] points to an array of pointers to char
// extracting the first word
char* a_word = strtok(string, " ");
// looping through the string to extract all other words
do
{
printf("\n%i %s\n", 1+n_of_words, a_word);
words[n_of_words] = malloc(1 + sizeof(a_word));
strcpy(words[n_of_words], a_word);
n_of_words++;
if (n_of_words >= MAX_N_OF_STRINGS) break;
a_word = strtok(NULL, " ");
} while (a_word != NULL);
printf("\n%d words at the end of the loop:\n\n", n_of_words);
for (int i = 0; i < n_of_words; i += 1)
{
printf("%i %s\n", 1 + n_of_words, words[i]);
free(words[i]); // deletes words[i]
}; // for()
free(words); // deletes the array
return 0;
};
As a result:
Please input a string of text: we have at least one byte
full string was 'we have at least one byte'
1 we
2 have
3 at
4 least
5 one
6 byte
6 words at the end of the loop:
1 we
2 have
3 at
4 least
5 one
6 byte
There are a few problems that could lead to a seg fault. First, I get warnings compiling your code:
../main.c: In function 'main':
../main.c:17:25: warning: implicit declaration of function 'strtok' [-Wimplicit-function-declaration]
words[n_of_words] = strtok(string, " ");
^~~~~~
../main.c:17:23: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
words[n_of_words] = strtok(string, " ");
^
../main.c:24:27: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
words[n_of_words] = strtok(NULL, " ");
All of this is because you didn't include the proper header for strtok
, namely string.h
. This could potentially cause problems because the default return type is assumed to be int
, which may not be large enough to hold a pointer.
Second, you are passing an incorrect size to fgets()
. The size should be the size of the buffer for holding the result. If the buffer is overflowed, undefined behavior results.
Finally, the words
array is declared with a size n_of_words
, which is zero at that point. This results in a zero size array. Arrays in C do not automatically grow.
Here is your code with these issues fixed:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
int n_of_words = 0;
#define MAX_STR_SZ 256
// asking for user input
char string[MAX_STR_SZ]; // <--- Use macro to define buffer size
printf("\nPlease input a string of text.\n\n");
fgets(string, sizeof string, stdin);
char * words[MAX_STR_SZ]; // <--- Should never be more words than characters in the buffer
// extracting the first word
words[n_of_words] = strtok(string, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
// looping through the string to extract all other words
while( words[n_of_words] != NULL )
{
n_of_words ++;
words[n_of_words] = strtok(NULL, " ");
printf("\n%i %s\n", n_of_words, words[n_of_words]);
}
sleep(10);
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.