Segmentation fault. Converting a string to an integer - c

I have a problem where I'm trying to turn a value from an array of string pointers to an integer value: token[1]. However, I get a segmentation fault whenever I don't specify an integer at the first index which in some cases I won't need a number. For example what if I just wanted to type the command: list. I would get a segmentation fault after. How do I store the convert the string value at token[1] to an integer, if an integer is present or not?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
int main(){
int ch, n = 1;
int i = 0;
int val = 0;
char str[512], *token[5], *act_token;
while(1){
printf("Enter text: ");
while((ch = getchar()) != '\n')
str[i++] = ch;
str[i] = '\0';
i = 0;
printf("string: %s\n", str);
int spaces = 0;
for(int counter = 0; counter < strlen(str) + 1; counter++){
if(str[counter] == ' '){
spaces++;
}
}
printf("Spaces: %d\n", spaces);
strtok(str, " ");
while(n <= spaces && (act_token = strtok(NULL, " "))){
token[n] = act_token;
n++;
}
token[n] = NULL;
n = 1;
// printf("token[1]: %s\n", token[1]);
for(int x = 1; x < spaces+1; x++){
printf("token[%d]: %s\n", x, token[x]);
}
if(isdigit(atoi(token[1])) != 0){
val = atoi(token[1]);
}
printf("value:%d\n", val);
}
return 0;
}

I don't know whether I understand you correctly. However, I have simply added some checks to prevent segfault that were occurring at varying points of the code. Tested with 'foo 3 33'. Formatting is poor.
int main(){
int ch, n = 1;
int i = 0;
int val = 0;
#define TOKEN_SZ 5
char str[512], *token[TOKEN_SZ+1], *act_token;
while(1){
printf("Enter text: ");
while((ch = getchar()) != '\n')
str[i++] = ch;
str[i] = '\0';
i = 0;
printf("string: %s\n", str);
int spaces = 0;
for(int counter = 0; counter < strlen(str) + 1; counter++){
if(str[counter] == ' '){
spaces++;
}
}
printf("Spaces: %d\n", spaces);
n=0;
strtok(str, " ");
while(n<TOKEN_SZ && n <= spaces && (act_token = strtok(NULL, " "))){
token[n] = act_token;
n++;
}
token[n] = NULL;
for(int i=0; token[i]; i++){
printf("%d token[%d]: %s\n", n,i, token[i]);
}
if(n>0 && (atoi(token[0])) != 0){
val = atoi(token[0]);
}
printf("value:%d\n", val);
}
return 0;
}
Update
bash> ./a.out
Enter text: list 2 4
string: list 2 4
Spaces: 2
2 token[0]: 2
2 token[1]: 4
value:2
Enter text:

Replace
if(isdigit(atoi(token[1])) != 0){
val = atoi(token[1]);
}
with
if(isdigit(token[1][0])) != 0){
val = atoi(token[1]);
}
The problem is that isdigit takes a character as its argument. Sure, the man page says it takes an integer, but that integer represents a character.
What your code is doing is:
convert token[1] to an integer (or 0 if it's not a valid integer)
determine whether that integer happens to match an ASCII digit
If so, convert it again, and save the value.
I doubt that's your intent.
My version checks whether the first character of token[1] is a digit, and converts the value if it is. Make sure you understand what token[1][0] means.
BTW, note that if you enter more than 5 space-separated words in your string, you'll store to tokens[6] and higher, which will produce undefined results (possibly crash.) Also, your program is wrong if the user enters more than two spaces between words.
Don't guess what strtok is going to do regarding how it detects and handles delimiters. Instead, let it do its job. Store the values as you get them. Either pick a limit value for the array where you're storing your results and exit the loop before exceeding it, or malloc space for more results as necessary. Here's an example:
char * tstr = str;
int tok_count = 0;
char *tok;
do {
tok = strtok(tstr, " ");
if (tok != NULL) {
token[tok_count++] = tok;
}
tstr = NULL;
} while (tok != NULL && tok_count < TOK_COUNT);
TOK_COUNT has to be at least 1, and should be the array size for tokens.

Related

How can I check if a users input is a string when using fgets without using the function isdigit?

I am receiving input that I should be putting into an array, and although I've already implemented methods to check if the array is too short/long, I cannot seem to get around to checking if the array contains non-numeric characters.
The array is separated by whitespace and always ends with EOF, and I have that part figured out too. Here are some methods I've tried but could not solve the issue. Am I doing something wrong with my code?
char *str;
long nums;
fgets (line, BUFFER, stdin);
nums = strtol(line, &str, 10);
if (str != '\0'){
printf("Invalid input z");
return 1;
}
//but line here only returns the first value before whitespace, which is != to EOF
My method of converting the input from fgets into input is by using strtok, before using atoi to convert it to an integer before storing it in the array. Is there a better/easier method that works that I'm missing here? Thanks!
EDIT: Here is how I am doing the array
int count = row * col;
for (int i = 0; i < row && !stop; i++){
for (int j = 0; j < col && !stop; j++){
num = strtok(NULL, " ");
if (num == NULL){
printf("Invalid input 1");
stop = true;
}else{
int curr = atoi(num);
grid[i][j] = curr;
}
}
}
Here's a quick example of what I think you're trying to do.
int main() {
char line[1000];
char *str;
long nums;
fgets (line, 1000, stdin);
char *next = strtok(line, " \n");
while (next)
{
nums = strtol(next, &str, 10);
if (*str != '\0') {
printf("Invalid input %s\n", next);
return 1;
}
printf("Found %ld\n", nums);
next = strtok(0, " \n");
}
return 0;
}

Count and get integers from a string using C

I am self teaching C programming.
I am trying to count number of int present in given string which are separated by space.
exp:
input str = "1 2 11 84384 0 212"
output should be: 1, 2, 11, 84384, 0, 212
total int = 6
When I try. It gives me all the digits as output which make sense since I am not using a right approach here.
I know in python I can use str.split (" ") function which can do my job very quickly.
But I want to try something similar in C. Trying to create my own split method.
#include <stdio.h>
#include <string.h>
void count_get_ints(const char *data) {
int buf[10000];
int cnt = 0, j=0;
for (int i=0; i<strlen(data); i++) {
if (isspace(data[i] == false)
buf[j] = data[i]-'0';
j++;
}
printf("%d", j);
}
// when I check the buffer it includes all the digits of the numbers.
// i.e for my example.
// buf = {1,2,1,1,8,4,3,8,4,0,2,1,2}
// I want buf to be following
// buf = {1,2,11,84384,0,212}
I know this is not a right approach to solve this problem. One way to keep track of prev and dynamically create a memory using number of non space digits encountered.
But I am not sure if that approach helps.
You want to build your number incrementally until you hit a space, then put that into the array. You can do this by multiplying by 10 then adding the next digit each time.
void count_get_ints(const char *data) {
int buf[10000];
int j = 0;
int current_number = 0;
// Move this outside the loop to eliminate recalculating the length each time
int total_length = strlen(data);
for (int i=0; i <= total_length; i++) {
// Go up to 1 character past the length so you
// capture the last number as well
if (i == total_length || isspace(data[i])) {
// Save the number, and reset it
buf[j++] = current_number;
current_number = 0;
}
else {
current_number *= 10;
current_number += data[i] - '0';
}
}
}
I think strtok will provide a cleaner solution, unless you really want to iterate over every char in the string. It has been a while since I did C, so please excuse any errors in the code below, hopefully it will give you the right idea.
#include <stdio.h>
#include <stdlib.h>
int main() {
char str[19] = "1 2 11 84384 0 212";
const char s[2] = " ";
char *token;
int total;
total = 0;
token = strtok(str, s);
while (token != NULL) {
printf("%s\n", token);
total += atoi(token);
token = strtok(NULL, s);
}
printf("%d\n", total);
return 0;
}
You can check the ascii value of each character by doing c-'0'. If it's between [0,9], then it's an integer. By having a state variable, when you're inside an integer by checking if a given character is a number of space, you can keep track of the count by ignoring white space. Plus you don't need a buffer, what happens if data is larger than 10,000, and you write pass the end of the buffer?, undefined behavior will happen. This solution doesn't require a buffer.
Edit, the solution now prints the integers that are in the string
void count_get_ints(const char *data) {
int count = 0;
int state = 0;
int start = 0;
int end = 0;
for(int i = 0; i<strlen(data); i++){
int ascii = data[i]-'0';
if(ascii >= 0 && ascii <= 9){
if(state == 0){
start = i;
}
state = 1;
}else{
//Detected a whitespace
if(state == 1){
count++;
state = 0;
end = i;
//Print the integer from the start to end spot in data
for(int j = start; j<end; j++){
printf("%c",data[j]);
}
printf(" ");
}
}
}
//Check end
if(state == 1){
count++;
for(int j = start; j<strlen(data); j++){
printf("%c",data[j]);
}
printf(" ");
}
printf("Number of integers %d\n",count);
}
I believe the standard way of doing this would be using sscanf using the %n format specifier to keep track of how much of the string is read.
You can start with a large array to read into -
int array[100];
Then you can keep reading integers from the string till you can't read anymore or you are done reading 100.
int total = 0;
int cont = 0;
int ret = 1;
while(ret == 1 && total < 100) {
ret = sscanf(input, "%d%n", &array[total++], &cont);
input += cont;
}
total--;
printf("Total read = %d\n", total);
and array contains all the numbers read.
Here is the DEMO
Example using strtol
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
int count_get_ints(int output[], int output_size, const char *input) {
const char *p = input;
int cnt;
for(cnt = 0; cnt < output_size && *p; ++cnt){
char *endp;
long n;
errno = 0;
n = strtol(p, &endp, 10);
if(errno == 0 && (isspace((unsigned char)*endp) || !*endp) && INT_MIN <= n && n <= INT_MAX){
output[cnt] = n;
while(isspace((unsigned char)*endp))
++endp;//skip spaces
p = endp;//next parse point
} else {
fprintf(stderr, "invalid input '%s' in %s\n", p, __func__);
break;
}
}
return cnt;
}
int main(void) {
const char *input = "1 2 11 84384 0 212";
int data[10000];
int n = sizeof(data)/sizeof(*data);//number of elements of data
n = count_get_ints(data, n, input);
for(int i = 0; i < n; ++i){
if(i)
printf(", ");
printf("%d", data[i]);
}
puts("");
}
Assuming you don't have any non-numbers in your string, you can just count the number of spaces + 1 to find the number of integers in the string like so in this pseudo code:
for(i = 0; i < length of string; i++) {
if (string x[i] == " ") {
Add y to the list of strings
string y = "";
counter++;
}
string y += string x[i]
}
numberOfIntegers = counter + 1;
Also, this reads the data between the white spaces. Keep in mind this is pseudo code, so the syntax is different.

Can't break a while loop. Reading undefined array size

I have this sequence of letters and numbers, in which the letters are always these four: s, S, m, M. The numbers can have any value. Since the size of the sequence is not given, I just can't use a for loop, so I decided to use a while loop, but I'm having issues on breaking the loop.
Some input examples are:
12 s 80 s 3 m 12 M 240 S 8 m 30 s 240 s 1440 S 8 m 18 s 60 M
5 m 120 s 30 s 360 S 6 M 5 s 42 S 36 M 8 m 66 M 3240 S 14 m
Here is my code so far:
#include <stdio.h>
int main () {
int n[100], i = 0;
char x[100];
while(x[i] != '\n')
{
scanf(" %d %c", &n[i], &x[i]);
printf("%d %c ", n[i], x[i]);
i++;
}
return 0;
}
Any toughts on how to break the loop, and have all this values saved correctly on the array?
like this
#include <stdio.h>
int main(void){
int n[100], i, j;
char x[100];
do {
for(i = 0; i < 100; ++i){
int ch;
while((ch = getchar()) != EOF && ch != '\n'){//check newline
if(ch == '-' || '0' <= ch && ch <= '9'){
ungetc(ch, stdin);//back to stream a character
break;
}
}
if(ch == EOF || ch == '\n')
break;
if(2 != scanf("%d %c", &n[i], &x[i])){
fprintf(stderr, "invalid format.\n");
i = 0;//End the outer do-while loop
break;
}
}
//print
for(j = 0; j < i; ++j){
printf("(%d, %c)", n[j], x[j]);
}
printf("\n");
} while(i != 0);//End with empty line
}
#include <stdio.h>
#define DATA_MAX_LEN 100
int main(void){
int n[DATA_MAX_LEN], i, len, loop_end;
char x[DATA_MAX_LEN], newline[2], ch;
while(scanf("%1[\n]", newline) != 1){//End with empty line(only newline), Need EOF check
for(loop_end = len = i = 0; i < DATA_MAX_LEN && !loop_end; ++i){
//format: integer character[space|newline]
if(scanf("%d %c%c", &n[i], &x[i], &ch) != 3)
loop_end = printf("invalid format.\n");
else if(ch == '\n')
loop_end = len = ++i;
else if(ch != ' ')
loop_end = printf("invalid format.\n");
}
for(i = 0; i < len; ++i){
printf("%d %c ", n[i], x[i]);
}
printf("\n");
}
}
scanf and fscanf have many problems so it's best to avoid them.
The general pattern for dealing with input is to create a large input buffer, and then process that into smaller chunks.
char line[4096];
fgets( line, sizeof(line), stdin );
Since line is reused it's ok to make it large enough to hold any reasonable input.
Now that you've read a line into memory, it's a string of known size to process as you like. sscanf (scanf on a string) doesn't have most of the problems of scanf, but it's also not suited to moving through a string. One approach is to split the string into tokens on whitespace with strtok, and process them alternately as letters and numbers.
const char sep[] = " \t\n";
bool expect_letter = false;
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
if( expect_letter ) {
printf("Letter %s\n", token);
expect_letter = false;
}
else {
printf("Number %s\n", token);
expect_letter = true;
}
}
If you want to store them in an array, it's bad practice to allocate what you hope is enough memory. You'll have to use an array that grows as needed. C does not have these built in. You can write your own, and it's a good exercise, but it's easy to get wrong. For production use one from a library such as Glib.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
int main() {
// Read a single line of input into a buffer.
char line[4096];
fgets( line, sizeof(line), stdin );
// Create arrays to hold letters and numbers, these will grow as needed.
GArray *numbers = g_array_new( FALSE, TRUE, sizeof(int) );
GArray *letters = g_array_new( FALSE, TRUE, sizeof(char) );
// Split the string on whitespace into tokens.
const char sep[] = " \t\n";
gboolean expect_letter = FALSE;
for(
char *token = strtok( line, sep );
token != NULL;
token = strtok( NULL, sep )
) {
if( expect_letter ) {
// Need an error check to ensure that `token` is a single character.
g_array_append_val( letters, token[0] );
expect_letter = FALSE;
}
else {
// strtol is a better choice, it has error checking
int num = atoi(token);
g_array_append_val( numbers, num );
expect_letter = TRUE;
}
}
// Print the numbers and letters.
for( guint i = 0; i < letters->len; i++ ) {
printf(
"%d%c\n",
g_array_index( numbers, int, i ),
g_array_index( letters, char, i )
);
}
}
Note that GLib provides its own boolean, so I switched to that instead of stdbool to keep things consistent.
As noted in the comments, this does not include checks that the token is what you expect. It's also possible to have a number with no letter, so checking that letters and numbers are the same size would be good. Or you can make a struct to hold the letter/number pairs and have a single list of those structs.

word length statistic C language

Can anyone help me to make that project.
Write a program that calculates statistics on word length for a sentence. The sentence isterminated by a ’.’ For each found length of a word the number of words of that length
is printed. Only those lengths that are found in the input are printed. Only letters from
a-z or A-Z are allowed to form words. Words are separated by a space. No punctuation
characters other than ’.’ are allowed. If any other input character is recognized or the
input is longer than 80 characters the program displays ”NOT VALID” (see Hints). Note,
that in the case that no word is present in the input, nothing is printed.
% u6_stats
Enter a sentence: Bolt was expected to use the super bark.
Length 2: 1
Length 3: 3
Length 4: 2
Length 5: 1
Length 8: 1
% u6_stats
Enter a sentence: Something wasn’t right.
NOT VALID
#include <stdio.h>
#include <conio.h>
void main() {
char s[100];
int numOfWords, lengthOfWord = 0;
int i = 0, j = 0;
printf("Enter the text : ");
fgets(s, sizeof(s), stdin);
numOfWords = 1;
while(s[i]!='\0') {
if(s[i] == ' ')
numOfWords++;
i++;
}
//printf("%d", numOfWords);
i = 0;
int help[numOfWords];
int l;
for(l = 0; l < numOfWords ; l++)
help[l] = 0;
while(s[i]!='\0') {
if(s[i] != ' ' && s[i] !='\n' && s[i]!='.' ) {
lengthOfWord++;
i++;
}else{
help[j] = lengthOfWord;
j++;
lengthOfWord = 0;
i++;
}
}
int repeat[80];
for(l = 0; l < 80 ; l++)
repeat[l] = 1;
int num = 1;
i=0,l=0;
for(i = 0;i<numOfWords;i++) {
for(l=i+1;l<numOfWords;l++)
if(help[i]==help[l]) {
repeat[l]='\0';
num++;
repeat[i] = num;
}
num = 1;
}
l=0;
for (l=0; l<numOfWords; l++)
if (repeat[l]!='\0' && help[--l]!=help[++l])
printf("Length %d: %d\n", help[l],repeat[l]);
}
So, the problem is that if i inpute a text like"abc abcd abc abc"
the result will be like "length 3: 3 length 4: 1 length 3: 2".
So when the program already compared 1st (here 3) element with otheres, this element will not be comparing again, but i have the 3d element with same length, and it that case, the program compare it with remained elements and print 2. How can i rework my code, if i dont wont to compare already compared elements.
Second problem is that i need to get results from lowest length till highst.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void invalid(void){
puts("NOT VALID");
exit(EXIT_FAILURE);
}
int main(void){
int length[80]={0};
int i, ch, word_len=0;
printf("Enter a sentence: ");
while(1){
ch=getchar();
if(isalpha(ch)){
++word_len;
} else if(ch == ' ' || ch == '.'){
if(word_len>80)
invalid();
if(word_len)
length[word_len-1]++;//-1: to 0 origin
if(ch == '.')
break;
word_len = 0;
} else {
invalid();
}
}
for(i=0;i<sizeof(length)/sizeof(*length);++i){
if(length[i])
printf("Length %d: %d\n", i+1, length[i]);
}
return 0;
}
A simple approach is with strtok (http://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm).
#include <stdio.h>
int numwords (char *str);
int main() {
char word[] = "This is a test - does it pass?";
int c = numwords(word);
printf("Words = %d\n", c);
return 0;
}
int numwords(char *str)
{
int n = 0;
for(str=strtok(str, " -.!,;"); str; str=strtok(NULL, " -.!,;"))
n++;
return n;
}

Seg Fault when counting shifts in insertion sort - C

I wrote the following to sort N integers read in from stdin in C, sort them using insertion-sort, and count the number of swaps that were needed to sort it for a SPOJ problem: http://www.spoj.com/problems/CODESPTB/
My code works for the sample inputs given and I've also tested with larger integer sets f larger values and everything seems to work fine. However, when I run it on SPOJ's online judge it fails with a Segmentation Fault at runtime. Unforunately, the creator of the problem on SPOJ has not made reviewing failures an option. I have no clue what's causing the seg fault. Does anything in my code jump out at you as to what might be causing it?
My Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFF 100
int main(int argc, char *argv[]){
char buffer[MAX_BUFF];
char *long_str;
int T, N;
long *a;
printf("Enter a T value between 1 and 5 inclusive: ");
bzero(buffer, MAX_BUFF);
fgets(buffer, MAX_BUFF - 1, stdin);
T = atoi(buffer);
if(T<1 || T>5){
printf("Error: T must be 1<=T<=5\n");
exit(0);
}
const char delim[2] = " ";
char *token;
while(T > 0){
printf("Enter a N value between 1 and 100000 inclusive: ");
bzero(buffer,MAX_BUFF);
fgets(buffer, MAX_BUFF-1, stdin);
N = atoi(buffer);
if(N<1 || N>100000){
printf("Error: N must be 1<=N<=100000\n");
exit(0);
}
int current_size = 0;
long_str = malloc(MAX_BUFF);
current_size = MAX_BUFF;
printf("Enter N integers separated by spaces: ");
if(long_str != NULL){
int c = EOF;
unsigned int i = 0;
while(( c = getchar() ) != '\n' && c != EOF){
long_str[i++]=(char)c;
if(i==current_size){
current_size = i + MAX_BUFF;
long_str = realloc(long_str, current_size);
}
}
long_str[i] = '\0';
}
token = strtok(long_str, delim);
a[0]=atol(token);
int i = 1;
while (token != NULL && i < N) {
token = strtok(NULL, delim);
if(token == NULL){
printf("Error, not enough ints specified, terminating\n");
exit(0);
}
a[i] = atol(token);
i++;
}
free(long_str);
int j, tmp, count;
count = 0;
for(i=1; i<N; i++){
j=i;
while(j>0 && a[j]<a[j-1]){
tmp = a[j];
a[j] = a[j-1];
a[j-1] = tmp;
j--;
count++;
}
}
T--;
}
}
You never allocate space for a:
long *a;
...
a[0]=atol(token);
...
a[i] = atol(token);
Unfortunately, one possibility of undefined behaviour is that it "seems to work fine".

Resources