I'm creating my own toUpper function in C, but keep getting a segmentation fault every time I attempt to run it. Can anyone provide me with any hints as to how to fix this problem?
int toUpper(char *str)
{
int i;
for(i=0;i< i <= strlen(str); i++) {
if(str[i] >= 97 && str[i] <= 122) {
str[i] = str[i] -32;
}
}
return(str[i]);
}
int main()
{
char string[20];
printf("Enter any string:\n");
scanf("%s", string);
char result= (char)(toUpper(string));
printf("The string in upper case is:%s\n", result);
}
You're running off the end of the string:
for(i=0;i< i <= strlen(str); i++) {
^--
e.g. a 10 char string has characters 0->9, but you're looping 0->10. Change <= to < so you stop at 9.
Plus, you haven't set any limit on your scanf, so if someone enters a 21 char string, you'll exceed the storage you've allocated the string array.
Recommend changing toUpper() to:
char *toUpper(char *str) {
size_t len = strlen(str);
size_t i;
for (i = 0; i < len; i++) {
if (str[i] >= 'a' && str[i] <= 'z') {
str[i] = str[i] - 'a' + 'A';
}
}
return str;
}
Use correct index range i < strlen(str) vs. i <= strlen(str). This is the main issue. #Marc B
Change return type. Suggested by #Weather Vane. like strcpy(), strcat()
Calculate string length once, rather than many times.
Use literals that match your goal: 'a' instead of 97. #marsh
Use size_t for index and length. That is the type return by strlen() and is the best type to use for array access. Makes a difference with huge strings, but not with these simple examples.
This code does depend on ASCII. This is often OK, but not completely portable.
Change 32 to -'a' + 'A' per #user295691
printf("The string in upper case is:%s\n", result);
result should be a char * but is a char. This is probably where your seg fault is happening. Other places include:
scanf("%s", string);
if the inputted string is longer than 19 chars, you could have problems due to string only being 20 chars long
for(i=0;i< i <= strlen(str); i++) {
if str for whatever reason doesn't have an ending 0, you could seg fault there as well.
Another major issue in the code is the for loop statement.
for(i=0;i< i <= strlen(str); i++)
^ ^
It's probably a typo, but the i < i < wont work.
Related
I am trying to write a function that changes all lowercase letters of a string to uppercase. Here is my code:
/**
* string_toupper - This function will replace all lowercase letters in
* the string pointed by str to uppercase
* #str: The string that will be checked for lowercase letters
*
* Return: The resulting string str, where all the letters are uppercase
*/
char *string_toupper(char *str)
{
int i;
for (i = 0; *str != '\0'; i++)
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
}
return (str);
}
And I tried it using:
#include <stdio.h>
int main(void)
{
char str[] = "Hello World!\n";
char *ptr;
ptr = string_toupper(str);
printf("%s\n", ptr);
printf("%s\n", str);
return (0);
}
But I get the following output:
Segmentation fault(core dumped)
My approach --> I will check the string if it has a lowercase letter. Then I will subtract 32 from the character if it matches to a lowercase character. I did this to make the character to uppercase, by subtracting 32 I am able to get the uppercase letter of the corresponding lowercase character I have found in the string.
But I am getting a Segmentation fault error, why is it happening?
change the for loop condition to for (i = 0; str[i] != '\0'; i++) since it should check every index.
char *string_toupper(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] =(int)str[i] - 32;
}
return (str);
}
By request, this is offered for education and debate.
Some workplaces or institutes insist on a particular style wrt curly braces, etc. I freelance...
Notice that the function name is not reproduced in a comment block. Bad habit that leads to satisfying supervisors with copy/paste of comment blocks that are WRONG and certainly misleading. Better to let the code explain itself by using conventional idioms and standard libraries.
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
char *string_toupper( char *str ) {
// Uppercase all lowercase letters found in 'str'.
// Return str after processing.
assert( str != NULL ); // Trust no-one, especially yourself
// Alternative for():: for( int i = 0; str[ i ]; i++ )
for( int i = 0; str[ i ] != '\0'; i++ )
str[ i ] = (char)toupper( str[ i ] ); // note casting.
return str;
}
int main( void ) {
char str[] = "Hello World!";
// No further use? Don't store return value; just use it.
printf( "%s\n", string_toupper( str ) );
printf( "%s\n", str );
return 0;
}
OP's key problem is well explained by Prithvish: wrong loop test.
// for (i = 0; *str != '\0'; i++)
for (i = 0; str[i] != '\0'; i++)
To help OP with How can I make my code work on every environment?, some thoughts for later consideration.
Future names
"Function names that begin with str, mem, or wcs and a lowercase letter may be added to the declarations in the <string.h> header." C17dr ยง 7.31.13
So do not code function names that begin str<lowercase> to avoid future collisions.
Indexing type
int i; is too narrow a type for long lines. Use size_t for array indexing.
Alternatively simply increment the pointer.
Test case with classification is...() functions
str[i] >= 'a' && str[i] <= 'z' is incorrect on systems where [a...z] are not continuous. (Uncommon these days - example EBCDIC).
Simplify with topper()
To convert any character to its uppercase equivalent:
str[i] = toupper(str[i]);
Use unsigned access
is..(x) and toupper(x) functions need unsigned char character values (or EOF) for x.
On soon to be obsolete rare non-2's complement systems, character string should be accessed as unsigned char to avoid stopping on -0.
Putting this together:
#include <ctype.h>
char *str_toupper(char *str) {
unsigned char *ustr = (unsigned char *) str;
while (*ustr) {
*ustr = toupper(*ustr);
ustr++;
}
return str;
}
There is a major mistakes in your code:
the test in for (i = 0; *str != '\0'; i++) in function string_toupper is incorrect: it only tests the first character of str instead of testing for the end of string. As coded, you keep modifying memory well beyond the
end of the string until you reach an area of memory that cannot be read or written, causing a segmentation fault. The code has undefined behavior. You should instead write:
for (i = 0; str[i] != '\0'; i++)
Also note that if (str[i] >= 'a' && str[i] <= 'z') assumes that the lowercase letters form a contiguous block in the execution character set. While it is the case for ASCII, you should not make this assumption in portable code.
Similarly, str[i] -= 32; is specific to the ASCII and related character sets. You should either use str[i] = str[i] - 'a' + 'A'; which is more readable or use the functions from <ctype.h>.
Here is a modified version:
#include <stdio.h>
/**
* string_toupper - This function will replace all lowercase letters in
* the string pointed by str with their uppercase equivalent
* #str: The string that will be checked for lowercase letters
*
* Return: The resulting string str, where all the letters are uppercase
*/
char *string_toupper(char *str) {
for (size_t i = 0; str[i] != '\0'; i++) {
if (str[i] >= 'a' && str[i] <= 'z')
str[i] = str[i] - 'a' + 'A';
}
return str;
}
int main() {
char str[] = "Hello World!\n";
char *ptr;
printf("before: %s\n", str);
ptr = string_toupper(str);
printf("result: %s\n", ptr);
printf(" after: %s\n", str);
return 0;
}
And here is a portable version of string_toupper():
#include <ctype.h>
#include <stddef.h>
char *string_toupper(char *str) {
for (size_t i = 0; str[i] != '\0'; i++) {
if (islower((unsigned char)str[i]))
str[i] = (char)toupper((unsigned char)str[i]);
}
return str;
}
I was trying to solve a problem in toph.co platform. I have made a code. It is not working as it should be. Giving me the correct output in some cases. But when I am trying a case with 'o' it is entering in a loop. And maybe the problem is there. But I am unable to find that out.
Problem link: https://toph.co/p/better-passwords
Please help me to solve the problem in my code. I am using c programming language. As I am new in programming, I am not getting the point that is wrong.
I have tried it in many ways. Modifying the code again and again. Now I am becoming mad.
#include <stdio.h>
#include<string.h>
int main()
{
char s[40], i, j;
int len;
gets(s);
len= strlen(s);
for(i=0; i<=len; i++)
{
if(s[i] == 's')
{
s[i]= '$';
}
else if(s[i] == 'i')
{
s[i]= '!';
}
else if(s[i] == 'o')
{
s[i]= '(';
for(j=len; j>i; j--)
{
s[j]=s[j-1];
len= strlen(s);
}
s[i+1]=')';
}
else
{
continue;
}
len= strlen(s);
}
if (s[0]>='a' && s[0]<='z')
{
s[0]= s[0]- 32;
}
int new_len=strlen(s);
s[new_len]='.';
puts(s);
return 0;
}
I expect the output Un$()ph!$t!cated. , but it is showing Un$()ph!$t!cated.....'Many unwanted charecter'.....
Your string null byte is missing after manipulations, easiest way to avoid such problems - is to initialize whole character array into zero bytes:
char s[40] = {0}, // was char s[40], uninitialized !
Also do you notice a compile message "warning: the `gets' function is dangerous and should not be used" ?
gets() is dangerous, because it is not protected from buffer overflow - try to run your program with very long string exceeding your buffer s capacity and you will get a crash :
* stack smashing detected *: terminated Aborted (core dumped)
Use fgets() instead of gets(), like so :
fgets(s, 39, stdin);
if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0'; // deleting newline character
Notice, that we read here BUFFER_SIZE - 1 characters here, i.e.- by 1 char less, than your buffer is able to hold (40), because if we enter long string which is of full buffer size,- then your code extending string will smash stack once again. You need to be serious about buffer overflows.
As most commentators wrote: you don't put the end-of-string character '\0' behind the extended string. Strings in C are marked by this extra character at the end. It is needed to find the end of a string.
Example: A string "abc" is actually a sequence of 4 characters, 'a', 'b', 'c', and '\0'. Its length is 3, and its s[3] contains '\0'.
Your loop:
for(j=len; j>i; j--)
{
s[j]=s[j-1];
len= strlen(s);
}
In the first turn of the loop the character at s[len] is replaced by the character at s[len-1]. This overwrites the original '\0' with the last (visible) character of your string.
If you change the loop into:
for (j = len; j > i; j--)
{
s[j + 1] = s[j];
}
the '\0' will be copied in the first run.
Note 1: Move the assignment to len behind the loop.
Note 2: Make sure that your variable s is big enough for all inputs.
Note 3: See the whitespace I use? Adopt a good code style and stick to it.
There are a couple of places in your code where you are overwriting the "\0".
These are:
s[j]=s[j-1];
And
s[new_len]='.';
So the rectified code would be....
int main()
{
char s[40], i, j;
int len;
gets(s);
len= strlen(s);
for(i=0; i<=len; i++)
{
if(s[i] == 's')
{
s[i]= '$';
}
else if(s[i] == 'i')
{
s[i]= '!';
}
else if(s[i] == 'o')
{
s[i]= '(';
for(j=len+1; j>i; j--) //j needs to be one more than the length
{
s[j]=s[j-1];
len= strlen(s);
}
s[i+1]=')';
}
else
{
continue;
}
len= strlen(s);
}
if (s[0]>='a' && s[0]<='z')
{
s[0]= s[0]- 32;
}
int new_len=strlen(s);
s[new_len]='.';//add a '.'
s[new_len+1] = '\0'; //add the terminating character
puts(s);
return 0;
}
This is my first post on stack overflow :)
I didn't find relevant post to my issue despite numerous posts on "counting words".
I started C 2 weeks ago. I have to return the number of words in a string, this is part of a larger exercise I m working on at the moment. I can't figure out why it doesn't work and I am kindly asking for some tips here.
ft_strlen(char *str) //counting nb of char in the string
{
int size;
size = 0;
while (str[size])
size++;
return (size);
}
int ft_word_count(char *str)
{
int i;
int size;
int count_word;
i = 0;
size = ft_strlen(str);
count_word = 0;
while (str[i] < size - 1) //counting nb of words in the string, I added "-1" to size to get rid of the '\0'
{
if (i <= 32 || i > 126 ) //defining what will make a word
count_word++;
i++;
}
return (count_word);
}
int main(void)
{
char str[]="Meine Frau liebt grosse Pferde";
ft_strlen(str);
printf("%d", ft_word_count(str));
return (0);
}
it returns 0 instead of 5, strangely, don't figure out why.
If I just use my strlen, it returns "30", as expected. So something is wrong with ft_word_count
Compiled with gcc.
Syntax is not concise but is part of the norm asked by my school.
thanks for your input
Charles
you should ignore multiple spaces for counting correct
i=0;
count_word=0;
while(str[i]>0)
{
if((str[i]!= ' '))
{
if(!toggle && str[i]!= ' ')
count_word++;
toggle=1;
}
else
toggle=0;
i++;
}
I believe that you meant to use logic more like this:
if(str[i] <= 32 || str[i] > 126) count_word++;
In the code that you posted, you are looking at the value of your index, not the character value in the string.
Even so, this is not why you are receiving "0" as a result. The cause of this is your while condition. You are checking to see if the numeric ASCII value within the string is greater than the length of the string... which I can assure you, it is. Therefore, you also want to change your white to be:
while(i < size - 1)
Personally, I would likely have checked for \n, space and \t instead, but to each his own!
The problem is these lines
while (str[i] < size - 1) // Here you compare the individual chars and
// the length of the string. That makes
// no sense
{
if (i <= 32 || i > 126 ) // Here you compare the index i and some
// fixed numbers. That makes no sense
count_word++;
i++;
}
It seems you have swapped the two, i.e. you use str[i] when you should use i and you use i when you should use str[i]
So if you change your code to:
while (i < size - 1)
{
if (str[i] <= 32 || str[i] > 126 )
count_word++;
i++;
}
You'll see that things start to make more sense. That code will print 4. That is still wrong but now you have some code that you can continue with.
A simple approach could be:
while (i < size - 1)
{
if (str[i] == ' ')
count_word++;
i++;
}
count_word++;
That code will print 5. However, the code is too simple as it count double spaces as words.
In other words - you need to add more code to handle such case but I guess that is part of the learning process. Good luck.
Error Part
while (str[i] < size - 1)
Here its checking with the ascii value at that place of string which will always be false and hence loop is not running.
Correct Way
while (i < size - 1)
{
if (str[i] == ' ')
count_word++;
i++;
}
count_word++;
There are multiple problems in your code:
while (str[i] < size - 1) is incorrect as you are comparing the value f the character to the size of the string instead of the index: it should be while (i < size).
if (i <= 32 || i > 126 ) is incorrect: it is not a proper way to check for word separators as non ASCII characters will not be considered part of the word and the encoding might not be ASCII anyway. You should instead use isspace() from <ctype.h>.
Furthermore, counting the spaces is not a way to count the words. You should instead count the number of transitions from space to non-space.
Here is a simpler version:
#include <ctype.h>
#include <stdio.h>
int ft_word_count(const char *str) {
unsigned char c, last = ' ';
int count = 0;
for (int i = 0; (c = str[i]) != '\0'; i++) {
if (!isspace(c) && isspace(last))
count++;
last = c;
}
return count;
}
int main(void) {
char str[] = "Meine Frau liebt grosse Pferde";
printf("%d\n", ft_word_count(str));
return 0;
}
I wrote a simple program to toggle string, I tried in my computer and IDEOne, I am receiving a weird string appended to the output. Am I missing something?
#include <stdio.h>
int main (int argc, char *argv[]) {
char input[100], output[100];
int length;
scanf("%s", input);
length = sizeof(input)/sizeof(input[0]);
for (int i = 0; input[i] != '\0'; i++) {
if (input[i] >= 97 && input[i] <= 122) {
output[i] = input[i] - 32;
} else if (input[i] >= 65 && input[i] <= 90) {
output[i] = input[i] + 32;
}
}
printf("%s\n", output);
return 0;
}
Link to IDEOne - https://ideone.com/NFlDJK
%s expects a null terminated string as an argument. You have to append a '\0' character at the end of output.
You don't terminate your output, i.e. you do not write the final \0-character that marks the end of a string. Hence, printf, which expects a 0-terminated string, probably prints some garbage. A simple solution would be to define output as
char output[100] = { 0 };
Thereby, output will be filled with \0 and anything you write in before will find some end then.
As pointed out in the comments, there are some more issues in the code which may lead to undefined behaviour or unexpected results.
First, you'll get a buffer overflow if you enter more than 99 characters (then yielding undefined behaviour). You could avoid this by using scanf("%99s", input).
Second, you may get an unexpectedly short result if your input contains some characters not triggering your toggle-expression. In your code, output would contain garbage at the relevant position; in the output = { 0 }-variant, the result would "end" at this point. Hence, an input like "abc1234DEF" might yield "ABC?#:-def"or "ABC", respectively. Add an else { output[i]=input[i]; } to overcome this.
Third, length = sizeof(input)/sizeof(input[0]) will always return 100, regardless of the actual number of characters entered. Note that sizeof(input) will be 100 and sizeof(input[0]) will 1 as compile time constants. To get the "length" of the string in terms of number of characters entered use strlen(input).
int main (int argc, char *argv[]) {
char input[100], output[100] = { 0 };
scanf("%99s", input);
size_t length = strlen(input);
for (int i = 0; i < length; i++) {
if (input[i] >= 97 && input[i] <= 122) {
output[i] = input[i] - 32;
} else if (input[i] >= 65 && input[i] <= 90) {
output[i] = input[i] + 32;
}
else {
output[i] = input[i];
}
}
printf("%s\n", output);
return 0;
}
the answer to the question is:
the output[] array must be NUL (0x00) terminated.
The '%s" format specifier in the call to printf() does not stop outputting bytes until it encounters a NUL.
Since the posted code failed to set the needed NUL byte, the "%s" will keep outputting bytes until it happens upon some random NUL byte.
This is undefined behavior and can lead to a seg fault event.
You can fix the problem by:
after the for() code block and before the printf() statement, insert the statement:
output[i] = '\0';
After your loop i is one more i.e you just have to put
Output[i]='\0';
And its done
#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';