Segmentation fault when listing the words in a sentence - c

int getter2(char str[])
{
int len=0;
scanf("%100[^\n]s",str);
while (str[len++] != '\0');
return len-1;
}
int wordmaker(char str[],char word[15][15],int len)
{
int i,temp=0,j=0;
for (i=0;i<len;i++){
if (((str[i]>='a') && (str[i]<='z')) || ((str[i]>='A') && (str[i]<='Z'))){
word[j][temp++] = str[i];
}
else{
j++;
temp=0;
}
}
for (i=0;i<15;i++)
for (j=0;j<15;j++)
printf("%c",word[i][j]);
}
int main()
{
char line[max],word[15][15];
int len;
printf("%d\n%s\n",getter2(line),line);
wordmaker(line,word,len);
}
core dumped.segmentation fault.the wordmaker function is faulty.t does'nt end.when i run the program i get the sentence i put properly along with proper length.the wordmaker function seems to be the problem.
can someone help me debug it.

I fixed some of the problems in the code and got it working. There's problem a though: If you do not input 15 words, it will print garbage (because of the for (i = 0; i < 15; i++) loop in wordmaker).
General points:
You do not need the s in your format string for scanf().
Return type of wordmaker should be void.
Added zero terminating byte to each string.
Printing strings instead of individual characters.
Assigned the return value of getter2 to len inside main.
All that is in the code:
/* str.c
* gcc -o str str.c -Wall
*/
#include <stdio.h>
/* As pointed by #BLUEPIXY, this should be 101 because of the format
* string of scanf. It will read 100 characters from stdin into the
* string, but it doesn't take into account the terminating NULL byte.
*/
#define max 101
int getter2(char str[])
{
int len = 0;
/* no need the trailing s in format string */
scanf("%100[^\n]", str);
while (str[len++] != '\0');
return len - 1;
}
/* changed return type to void, since you're not returning anything */
void wordmaker(char str[], char word[15][15], int len)
{
int i, temp = 0, j = 0;
for (i = 0; i < len; i++) {
if (((str[i] >= 'a') && (str[i] <= 'z'))
|| ((str[i] >= 'A') && (str[i] <= 'Z'))) {
word[j][temp++] = str[i];
} else {
/* put the terminating null byte on each string */
word[j][temp] = 0x0;
j++;
temp = 0;
}
}
/* print the strings, not their characters
*
* If you use a loop to print characters, you need to have 15 byte
* strings, otherwise you're gonna print garbage.
*/
for (i = 0; i < 15; i++)
printf("%s\n", word[i]);
}
int main()
{
char line[max], word[15][15];
int len;
/* here a little modification to initialize the variable 'len' */
printf("%d\n%s\n", (len = getter2(line)), line);
wordmaker(line, word, len);
}
As a side note, if you include ctype.h, you can change ((str[i] >= 'a') && (str[i] <= 'z')) || ((str[i] >= 'A') && (str[i] <= 'Z')) for isalpha(str[i]), which is clearer. The isalpha() manual.

Related

counting individual characters in c

I’m working on a project called readability. the user input a text and the code should then use the coleman-liau function to determine the reading level. But in order to use this fuktion you have to determine the number of words, letters and sentences. Right now I’m busy counting the letters. So I wanted to ask how to count individual characters in c. right now this is my code:
int count_letters (string text)
{
int count_letters = 0;
int numb = 0;
for (int i = 0, n = strlen(text); i < n; i++)
{
if (text[i] != '')
{
count_letters++;
}
}
return count_letters;
}
You can either use isalpha() or "improvise".
This will work for the ASCII character set:
#include <stdio.h>
int count_letters(const char *str)
{
int count = 0, i = 0;
for (; str[i] != '\0'; i++)
{
if ((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z'))
{
/* any character within this range is either a lower or upper case letter */
count++;
}
}
return count;
}
int main(void)
{
char *str = "Hello\n world hello123#";
printf("%d\n", count_letters(str));
return 0;
}
or use isalpha(), also supports your current locale.
#include <ctype.h>
int count_letters(const char *str)
{
int count = 0, i = 0;
for (; str[i] != '\0'; i++)
{
if (isalpha((unsigned char)str[i]))
{
count++;
}
}
return count;
}
EDIT: As Andrew mentioned, to be pedantic, you better pass an unsigned char as argument to isalpha() to avoid any undefined behavior that might arise due to the signed type of str.

Writing a C function to take in an english sentence as parameter and return the longest length word in the sentence

I have an assignment that requires me to write a function to take in an array containing an English sentence and return the length of the longest word in that sentence. This is the code I have so far:
int longWordLength(char *s); // Function prototype
int main() {
char str[80], *p;
printf("Enter a string: \n");
fgets(str, 80, stdin);
if (p = strchr(str,'\n'))
*p = '\0'; //converts newline to null
printf("longWordLength(): %d\n", longWordLength(str));
return 0;
}
int longWordLength(char *s) {
int count = 0, max = 0;
while (*s++ != '\0') {
if ((*s >= 'a' && *s <= 'z') || (*s >= 'A'&& *s <= 'Z')) {
count++;
} else {
if (count > max) {
max = count;
count = 0;
} else
count = 0; // word is not the longest
}
}
return max;
}
I have tried for a long time to diagnose the issue but to no avail.
This works with certain test case like:
Test Case 1:
Enter a string:
I am happy.
longWordLength(): 5
but for a test case like
Test Case 4:
Enter a string:
Hello
longWordLength(): 4 <- it prints 4 instead of 5.
I am not allowed to use any library other than the <string.h> as it is for my school assignment. Seeking anyone's kind guidance on my issue as I really can't seem to figure out the issue. Thank you in advanced.
The problem is in while (*s++ != '\0') {: you increment the string pointer before testing the character it points to. Just change to code to:
for (; *s != '\0'; s++) {
...
Note however that the last word will not be tested the maximum length if it is not followed by some separator such as a space or a newline, which you would have stripped.
Note that stripping the trailing newline is not required for longWordLength() to determine the correct count.
Here is a modified version:
#include <stdio.h>
int longWordLength(const char *s); // Function prototype
int main() {
char str[80];
printf("Enter a string: \n");
if (!fgets(str, sizeof str, stdin))
return 1;
// no need to strip the newline for this test:
printf("longWordLength(): %d\n", longWordLength(str));
return 0;
}
int longWordLength(const char *s) {
int count = 0, max = 0;
for (;; s++) {
if ((*s >= 'a' && *s <= 'z') || (*s >= 'A'&& *s <= 'Z')) {
count++;
} else {
if (count > max) {
max = count;
}
if (*s == '\0')
break;
count = 0; // reset the counter for the next word
}
}
return max;
}

Writing my own atoi function

I am trying to convert a string of numerical characters to their corresponding integral form. Please suggest what is wrong with the code. I would like to stick with pointers. I understand that the pointer str points to the first character in my string. So, each time I call my function in the loop, I want the pointer to increment by 1, and add the value of the character to one node in my array. For some reason, though I am unable to do so. Here is the code.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
int ctoi(char *c);
int main (void)
{
char *str;
int A[20];
int i = 0;
str = (char*) malloc(20 * sizeof(char));
printf("Input the string. ");
scanf("%s", str);
while(str != '\0')
{
A[i] = ctoi(str);
i++;
str++;
}
for(i = 0; i < strlen(str); i++)
printf("%d", A[i]);
getchar();
getchar();
return 0;
}
int ctoi(char *c)
{
int a;
a= *c - '0';
return a;
}
for (i=0;i<strlen(str);i++)
printf("%d", A[i]);
Here strlen will return 0 because you updated str in your previous loop .Replace it with :
for(i=0;i<len;i++)
where len is the length of your input string .Find it before using str in while loop
while(str!='\0') should be `while(*str!='\0')`
. You will get it . But for writing your own atoi function you dont need to store the number in an array
Please try this it works, the myatoi() function was lifted perhaps 20 years ago from the classic "THE C PROGRAMMING LANGUAGE" , get the book.
#include <stdio.h>
main()
{
char temp[99];
strcpy(temp , "34");
printf( "\n %d " , myatoi(temp));
strcpy( temp , "8642");
printf( "\n %d " , myatoi(temp));
}
int myatoi( char s[])
{
int i,n,sign;
// skip white space
for( i=0 ; s[i]==' ' || s[i]=='\n' ||s[i]=='\t';i++) ;
sign=1;
if( s[i]=='+' || s[i]=='-')
sign=( s[i++]=='+' ? 1 : -1 );
for( n=0; s[i]>='0' && s[i]<='9' ; i++)
n=10*n+s[i]-'0' ;
return(sign*n);
}
OP's code needs a few (at least 2) fixes to mostly work. See ***
int main (void)
{
char *str;
int A[20];
int i = 0;
// *** Cast not needed, '* sizeof(char)' not needed
str = malloc(20);
printf("Input the string. ");
scanf("%s", str);
// ***
char *str_original = str;
while(*str != '\0')
{
A[i] = ctoi(str);
i++;
str++;
}
// ***
str = str_original;
for(i = 0; i < strlen(str); i++)
printf("%d", A[i]);
// ***
free(str); // Good to return memory
str = NULL;
getchar();
getchar();
return 0;
}
A simple way to convert a string to an int
int strtoi(const char *s) {
int sum = 0;
char ch;
char sign = *s;
if (*s == '-' || *s == '+') s++;
while ((ch = *s++) >= '0' && ch <= '9') {
sum = sum * 10 - (ch - '0');
}
if (sign != '-') {
sum = -sum;
}
return sum;
}
Notes: This code accumulates the sum on the negative side of 0 to avoid UB when trying to parse the string for INT_MIN. Modified code could skip leading white-space, add text error detection, overflow detection, etc.
Here is my custom atoi funtion, who handle unsigned int with debug gestion:
int my_getnbr(char *str)
{
int nb;
int sign;
int i;
nb = 0;
sign = 0;
i = -1;
if (!str)
return (0);
while (str[++i])
if (str[i] < '0' && str[i] > '9' && str[i] != '-' && str[i] != '+')
return (0);
i = 0;
while (str[i] != '\0' && (str[i] == '-' || str[i] == '+'))
if (str[i++] == '-')
++sign;
while (str[i] && (str[i] >= '0' && str[i] <= '9'))
{
nb = (nb * 10) + (str[i++] - '0');
if (str[i] == ' ')
i++;
}
return (((sign % 2) == 1) ? ((nb) * (-1)) : (nb));
}
tested with that main:
int main()
{
printf("%d\n", my_getnbr("-42"));
printf("%d\n", my_getnbr("-+-+--42"));
printf("%d\n", my_getnbr("-0"));
printf("%d\n", my_getnbr("590310"));
return (0);
}
No leaks, here is the result:
-42
42
0
590310
Firstly
while(str!='\0') should be
while(*str!='\0')
You should compare the content, not the address.
And while printing the returned data, you are doing
for(i=0;i<strlen(str);i++)
printf("%d", A[i]);
str already parsed till the last. So length would probably be 0.
Change your while loop to
while(*str!='\0')
{
A[i]=ctoi(*str);
i++;
str++;
}
And your function to
int ctoi(char c)
{
int a;
a= c-'0';
return a;
}
There are several approaches for a simple atoi replacement without the base conversion flexibility in strtol. The simplest is generally to find the length of the string to convert, and then work backward toward the front of the string preforming the conversion from string to integer as you go. A quick example would be:
/* a quick atoi replacement */
int atoi2 (char *s)
{
int nmax = (1ULL << 31) - 1; /* INT_MAX */
long long n = 0; /* the number to return */
size_t m = 1; /* multiplier for place */
size_t l = 0; /* length of string */
char *p = s;
while (*p++) l++; /* get string length */
p -= 2; /* position at last char */
while (l--) /* for each char in string */
{ /* verify a digit or '-' sign */
if ((*p >= '0' && *p <= '9') || *p == '-')
{
if (*p == '-') { /* if '-' is first char */
if (p == s) n = -n; /* negate value */
}
else { /* otherwise normal conversion */
n += (*p - '0') * m;
if (n > nmax) { /* prevent overflow */
fprintf (stderr, "atoi2() error: conversion > INT_MAX.\n");
exit (EXIT_FAILURE);
}
m *= 10;
}
}
p--;
}
return (int) n;
}
A simple driver program to test could be:
#include <stdio.h>
#include <stdlib.h>
int atoi2 (char *s);
int main (int argc, char **argv) {
if (argc < 1) return 1;
printf ("\n string : %s, conversion : %d\n\n",
argv[1], atoi2 (argv[1]));
return 0;
}
Example Use/Output
$ ./bin/atoi2 321
string : 321, conversion : 321
$ ./bin/atoi2 -321
string : -321, conversion : -321
$ ./bin/atoi2 2147483647
string : 2147483647, conversion : 2147483647
$ ./bin/atoi2 2147483648
atoi2() error: conversion > INT_MAX.
If you have any questions, please do not hesitate to ask.
Here is a custom atoi function that avoids using most of the standard library functions
/*** _atoi - finds the first set of integers in a given string
* #s: string entered
* Return: first number sequence
**/
int _atoi(char *s)
{
int length = 0, negativeCount = 0, count = 0, num = 0;
while (s[length] != '\0')
{
length++;
}
while (count < length)
{
if (s[count] == '-')
{
negativeCount++;
}
if (s[count] >= 48 && s[count] <= 57)
{
/* ascii values for numbers */
for (; s[count] >= 48 && s[count] <= 57; count++)
{
num = (10 * num - (s[count] - 48));
}
break;
}
count++;
}
if (negativeCount % 2 != 0)
{
return (num);
}
else
{
return (-num);
}
}

add a space infront of capitals?

How do i add a space in front of capital letters in a string?
I am writing a c code for school that requires a function that adds a space in front of every capital letter in a concantenated sentence
e.g.
"HelloHowAreYou"
should look like
Hello How Are you
this what I have tried and as far as I got
int i;
i = 1;
while (str[i] != '\0')
{
if (str[i] >= 'A' && str[i] <= 'Z')
i = i + 1;
}
can anyone help?
To see why this wouldn't work try running your code with a pencil on a piece of paper. When you see a capital letter, all you do is skipping the index. Moreover, you never do any copying (and you do need to copy, because the letters after the capital ones need to move).
To figure out what to do, think of doing the move from the back: walk the indexes down from the end, inserting a space after each capital letter that you encounter.
There is only one wrinkle to this - knowing where the updated string ends. That's easy to compute, though, if you add the number of capital letters to the length of the string.
Of course you need to be sure that the updated string is going to fit in the space of the old string.
char str[100];
scanf("%50s", str);
int len = strlen(str);
if (len == 0) return; // Stop if the string is empty.
for (int i = 1 ; str[i] != '\0' ; i++) {
if (str[i] >= 'A' && str[i] <= 'Z')
len++;
}
int pos = strlen(str);
while (pos > 0) {
str[len] = str[pos--];
if (str[len] >= 'A' && str[len] <= 'Z') {
str[--len] = ' ';
}
len--;
}
printf("%s\n", str);
Demo.
How about
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
char *
addspaces (const char *src)
{
/* first find the length of the required string */
int l = 1; /* to allow for terminating NUL */
const char *s;
char *dest;
char *d;
for (s = src; *s; s++, l++)
if (isupper (*s))
l++;
/* now allocate memory for the string */
dest = malloc (l);
if (!dest)
return NULL;
/* now copy the original string into the buffer */
for (s = src, d = dest; *s;)
{
if (isupper (*s))
*d++ = ' ';
*d++ = *s++;
}
*d = 0;
return dest;
}
int
main (int argc, char **argv)
{
char *test = "AddSpacesToThisString";
char *out = addspaces (test);
printf ("Result: %s\n", out);
free (out);
exit (0);
}
You can see it working here: http://ideone.com/eKMIV0
This has the advantage of dynamically allocating the return buffer, rather than relying on a fixed length string.

Removing spaces and special characters from string

How do you remove spaces and special characters from a string?
I couldn't find a single answer while googling. There were a lot related to other languages, but not C. Most of them mentioned the use of regex, which isn't C standard (?).
Removing a simple space is easy:
char str[50] = "Remove The Spaces!!";
Then a simple loop with a if-statement:
if (str[i] != ' ');
Output would be:
RemoveTheSpaces!!
What do I add to the if-statement so it would recognize special characters and remove them?
My definition of special characters:
Characters not included in this list:
A-Z a-z 0-9
This is probably not the most efficient way of achieving this but it will get the job done fairly fast.
Note: this code does require you to include <string.h> and <ctype.h>
char str[50] = "Remove The Spaces!!";
char strStripped[50];
int i = 0, c = 0; /*I'm assuming you're not using C99+*/
for(; i < strlen(str); i++)
{
if (isalnum(str[i]))
{
strStripped[c] = str[i];
c++;
}
}
strStripped[c] = '\0';
There are millions of different ways this can be done. Here is just one example that is not using any additional storage and performs the removal of unneeded characters "in-place":
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
static void my_strip(char *data)
{
unsigned long i = 0; /* Scanning index */
unsigned long x = 0; /* Write back index */
char c;
/*
* Store every next character in `c` and make sure it is not '\0'
* because '\0' indicates the end of string, and we don't want
* to read past the end not to trigger undefined behavior.
* Then increment "scanning" index so that next time we read the
* next character.
*/
while ((c = data[i++]) != '\0') {
/* Check if character is either alphabetic or numeric. */
if (isalnum(c)) {
/*
* OK, this is what we need. Write it back.
* Note that `x` will always be either the same as `i`
* or less. After writing, increment `x` so that next
* time we do not overwrite the previous result.
*/
data[x++] = c;
}
/* else — this is something we don't need — so we don't increment the
`x` while `i` is incremented. */
}
/* After all is done, ensure we terminate the string with '\0'. */
data[x] = '\0';
}
int main()
{
/* This is array we will be operating on. */
char data[512];
/* Ask your customer for a string. */
printf("Please enter a string: ");
if (fgets(data, sizeof(data), stdin) == NULL) {
/* Something unexpected happened. */
return EXIT_FAILURE;
}
/* Show the customer what we read (just in case :-)) */
printf("You have entered: %s", data);
/*
* Call the magic function that removes everything and leaves
* only alphabetic and numberic characters.
*/
my_strip(data);
/*
* Print the end result. Note that newline (\n) is there
* when we read the string
*/
printf("Stripped string: %s\n", data);
/* Our job is done! */
return EXIT_SUCCESS;
}
I put a lot of comments in there so hopefully the code doesn't need explanation. Hope it helps. Good Luck!
This is just a silly suggestion.
char ordinary[CHAR_MAX] = {
['A']=1,['B']=1,['C']=1,['D']=1,['E']=1,['F']=1,['G']=1,['H']=1,['I']=1,
['J']=1,['K']=1,['L']=1,['M']=1,['N']=1,['O']=1,['P']=1,['Q']=1,['R']=1,
['S']=1,['T']=1,['U']=1,['V']=1,['W']=1,['X']=1,['Y']=1,['Z']=1,
['a']=1,['b']=1,['c']=1,['d']=1,['e']=1,['f']=1,['g']=1,['h']=1,['i']=1,
['j']=1,['k']=1,['l']=1,['m']=1,['n']=1,['o']=1,['p']=1,['q']=1,['r']=1,
['s']=1,['t']=1,['u']=1,['v']=1,['w']=1,['x']=1,['y']=1,['z']=1,
['0']=1,['1']=1,['2']=1,['3']=1,['4']=1,['5']=1,['6']=1,['7']=1,['8']=1,
['9']=1,
};
int is_special (int c) {
if (c < 0) return 1;
if (c >= CHAR_MAX) return 1;
return !ordinary[c];
}
void remove_spaces_and_specials_in_place (char *str) {
if (str) {
char *p = str;
for (; *str; ++str) {
if (!is_special(*str)) *p++ = *str;
}
*p = '\0';
}
}
Using your if statement:
if (str[i] != ' ');
With a little logic (the characters have to be in the range a-z or A-Z or 0-9:
If ( !('a' <= str[i] && 'z' >= str[i]) &&
!('A' <= str[i] && 'Z' >= str[i]) &&
!('0' <= str[i] && '9' >= str[i])) then ignore character.
This is Ascii Code Range
Char:Dec
0:48, 9:57
A:65, Z:90
a:97, z:122
try this:
char str[50] = "Remove The Spaces!!";
int i =0;
for(; i<strlen(str); i++)
{
if(str[i]>=48 && str[i]<=57 || str[i]>=65 && str[i]<=90 || str[i]>=97 && str[i]<=122)
//This is equivalent to
//if(str[i]>='0' && str[i]<='9' || str[i]>='A' && str[i]<='Z' || str[i]>='a' && str[i]<='z')
printf("alphaNumeric:%c\n", str[i]);
else
{
printf("special:%c\n", str[i]);
//remove that
}
}
#include <stdio.h>
#include <string.h>
main()
{
int i=0, j=0;
char c;
char buff[255] = "Remove The Spaces!!";
for(; c=buff[i]=buff[j]; j++){
if(c>='A' && c<='Z' || c>='a' && c<='z' || c>='0' && c<='9'){
i++;
}
}
printf("char buff[255] = \"%s\"\n", buff);
}
include < stdio.h >
int main()
{
char a[100];
int i;
printf("Enter the character : ");
gets(a);
for (i = 0; a[i] != '\0'; i++) {
if ((a[i] >= 'a' && a[i] <= 'z') || (a[i] >= 'A' && a[i] <= 'Z')
|| (a[i] - 48 >= 0 && a[i] - 48 <= 9)) {
printf("%c", a[i]);
} else {
continue;
}
}
return 0;
}

Resources