Segmentation Fault, but I have no infinite loops... I think - c

New to C syntax, so perhaps I'm just making a dumb error. I'm trying to implement the strcat() function myself by using the exact same process. My copycat function is strcat406().
I keep getting segmentation fault as an error when trying to run the program.
EDIT: The first while loop in strcat406() is my attempt at getting around the strlen() function. I'm trying to avoid using the built in operations.
EDIT2: Okay, so as people pointed out, I replaced the '\n' to '\0'. Stupid mistake. Then I fixed the whole thing by removing the 'string1[i] = string[i]'. That way the first loop just iterates to determine i (the length of string1), then string2 is added to string1 in the second while loop. Corrections in code below.
#include <stdio.h>
char *strcat406(char string1[ ], char string2[ ]) {
int i = 0, j = 0;
while (string1[i] != '\0') { //replaced '\n' with '\0'
//removed: string1[i] = string1[i];
i++;
}
while (string2[j] != '\0') { //replaced '\n' with '\0'
string1[i+j] = string2[j];
j++;
}
string1[i+j] = '\0';
return string1;
}
int main() {
char str1[81], str2[81];
char again = 'y', newline;
while (again == 'y') {
printf("Enter a string\n");
scanf("%s", str1);
printf("Enter another string\n");
scanf("%s", str2);
printf("The concatention is %s\n", strcat406(str1, str2));
printf("Second test: The concatenation is %s\n", str1);
printf("The second string is still %s\n", str2);
printf("Again? (y/n)\n");
scanf("%c%c", &newline, &again);
}
}

The problem is that your while loops are looking for a newline character to terminate, but scanf("%s", ...) won't include the ending newline in the scanned string. You should look for '\0' to terminate those loops.
By the way... the title of this question reflects a misunderstanding. You said you're getting a segfault, but "have no infinite loops". Segfaults are not normally caused by infinite loops. They are commonly caused by dereferencing a null pointer, or a pointer which is "bad" in some other way. Note that array indexing is a form of pointer dereference, so using a "bad" array index is just the same thing.

A string is an array of characters containing a terminating null character '\0', not a newline character '\n'. Therefore, in strcat406 function, you should check the value for the null byte and not the newline character. Note that str2 must be large enough for string2 to be appended to it else it will cause buffer overflow invoking undefined behaviour. Also note that the lengths of both the strings string1 and string2 should each be less than 81 and the sum of their lengths should be less than 81 + 81 == 162.
#include <stdio.h>
char *strcat406(char string1[], char string2[]) {
int i = 0, j = 0;
// increment i till the terminating null byte is reached
while(string1[i++]) ; // the null statement
i--; // reset i to the index of the null byte
// copy the characters from string2 to string1 till and
// including the terminating null byte of string2
while((string1[i++] = string2[j++])) ; // the null statement
return string1;
}
int main(void) {
char str1[81], str2[81];
char again = 'y';
while(again == 'y') {
printf("Enter a string\n");
scanf("%s", str1);
printf("Enter another string\n");
scanf("%s", str2);
printf("The concatention is %s\n", strcat406(str1, str2));
printf("Second test: The concatenation is %s\n", str1);
printf("The second string is still %s\n", str2);
printf("Again? (y/n)\n");
// note the leading space in the format string of scanf.
// this reads and discards the newline left in the buffer in
// the previous scanf call
scanf(" %c", &again);
}
return 0;
}

The problem is that you are writing the result of the concatenation on top of one of the input strings. At the moment the first loop (over string1) does nothing; it is just copying string1 on top of itself character by character. I think you might be getting confused between the newline character '\n' and the string termination character '\0' as well.
The reason you are getting segfaults is that in the second loop you start writing onto the memory that follows the first input string. Only 81 characters of memory are reserved for it, but you might write more than that for the concatenation.
I think the answer would be to create a new string to contain the result of your function. You need to find out how long it needs to be by looping over the input strings first, counting their length. Then when you copy the two strings into the result you will only use the space that you have reserved for it in memory. Also you won't change the input as part of the function, which is another problem with the current method.

Related

When I print my string it prints more than it's length

My Code
char str[100];
scanf("%s\n",str);
char str2[2];
scanf("%c\n",&str2[0]);
scanf("%c\n",&str2[1]);
printf("%s",str2);
Input
abbcde
b
c
Output
bcabbcde
If str2 is of length two only why all this extra thing comes from,I have checked that input has been recorded correctly for both strings.
The working code will be like
#include <stdio.h>
int main()
{
char str[100];
scanf("%s",str);
char str2[3];
scanf(" %c",&str2[0]);
scanf(" %c",&str2[1]);
str[2]='\0';
printf("%s",str2);
return 0;
}
Fix 1:
Unrelated: trailing whitespace characters such as \n in scanf() -- #ex_nihilo already given a comment on this.
Fix 2:
Space before %c removes any white space (blanks, tabs, or newlines)
Fix 3:
If str2 is a string then the end character should be '\0' and we need to add this explicitly. For this we need to increase the size of str2 array to 3.
When I print my string it prints more than it's length
Code did not attempt to print a string.
printf("%s",str2); requires str2 to be a string. str[2] is not a string as it lacks a null character. The result is undefined behavior (UB).
To print a character array like a string, even if it lacks a null character, use a precision. Printing stops when the precision or a null character is reached.
// printf("%s",str2);
printf("%.*s", 2, str2);
Alternatively, make certain str2[] contains a null character and print as before.
if str2 is string it most end with \0 and it length should be 3.
look:
int main()
{
char str[100];
scanf("%s", str);
char str2[3];
scanf(" %c", &str2[0]);// add space
scanf(" %c", &str2[1]);// add space
str2[2] = '\0';
printf("%s", str2);
}
also you shouldn't add this \n to your scanf because when you press enter it will automatically go to next line ,but when you add \n to scanf(after data)it will wait for something except new line or white space to terminate.

Counting the Whole String Including The Spaces in C

I'm trying to set up a code that counts the whole string and doesn't stop after the first space that it finds. How do I do that?
I tried this kind of code but it just counts the first word then goes to display the number of letters in that first word.
So far this is what I have tried.
int main(){
char get[100];
int i, space=0, len=0, tot;
scanf("%s", get);
for (i=0; get[i]!='\0'; i++)
{
if (get[i] == ' ')
space++;
else
len++;
}
tot = space + len;
printf("%i", tot);
}
And
int main(){
char get[100];
int len;
scanf("%s", &get);
len = strlen(get);
printf("%i", len);
}
But would still get the same answer as the first one.
I expected that if the
input: The fox is gorgeous.
output: 19
But all I get is
input: The fox is gorgeous.
output: 3
strlen already includes spaces, since it counts the length of the string up to the terminating NUL character (zero, '\0').
Your problem is that that the %s conversion of scanf stops reading when it encounters whitespace, so your string never included it in the first place (you can verify this easily by printing out the string). (You could fix it by using different scanf conversions, but in general it's easier to get things right by reading with fgets – it also forces you to specify the buffer size, fixing the potential buffer overflow in your current code.)
The Answer by Arkku is correct in its diagnose.
However, if you wish to use scanf, you could do this:
scanf("%99[^\n]", get);
The 99 tells scanf not to read more than 99 characters, so your get buffer won't overflow. The [^\n] tells scanf to read any character until it encounters the newline character (when you hit enter).
As Chux pointed out, the code still has 2 issues.
When using scanf, it is always a good idea to check its return value, which is the number of items it could read. Also, indeed the \n remains in the input buffer when using the above syntax. So, you could do this:
if(scanf("%99[^\n]", get) == 0){
get[0] = 0; //Put in a NUL terminator if scanf read nothing
}
getchar(); //Remove the newline character from the input buffer
I will take one example to explain the concept.
main()
{
char s[20], i;
scanf("%[^\n]", &s);
while(s[i] != '\0') {
i++;
}
printf("%d", i);
return 0;
}
i have used c language and u can loop through the ending the part of the string and you will get the length. here i have used "EDIT SET CONVESRION METHOD" to read string, you can also gets to read.

Calculate length of string without using strlen() function

Having a doubt regarding a very simple C code. I wrote a code to calculate the length of a string without using the strlen function. The code below works correctly if i enter a string with no spaces in between. But if i enter a string like "My name is ---", the length shown is the length of the word before the first white space, which in the example, would be 2. Why is that? Aren't white space and null character two different characters? Please guide me as to how i can change the code so that the entire string length is returned?
char s[1000];
int length = 0;
printf ("Enter string : ");
scanf ("%s", s);
for (int i = 0; s[i] != '\0'; i++)
{
length++;
}
printf ("Length of given string : %d", length);
It is because scanf with %s reads until it finds white space.
from man scanf
Matches a sequence of non-white-space characters; the next pointer
must be a pointer to character array that is long enough to hold the
input sequence and the terminating null byte ('\0'), which is added
automatically. The input string stops at white space or at the maximum
field width, whichever occurs first.
If you want read until \n including white space you can do as below.
scanf("%999[^\n]", s);
Or you could use fgets.
scanf reads the data until "\0" or "\20". So use "fgets" method which reads the data until "\n" (next line) with "stdin",
Example Program:
#include <stdio.h>
int main() {
char s[100];
printf("Input String: ");
fgets(s, sizeof(s), stdin);
printf("\nLength of the string is = %d", printf("%s"), s);
return 0;
}

Allocating Memory to String at runtime

I am writing a program to count the occurrence of '2' followed by '1' in a sting.
I dynamically allocated string
Code is:
#include <stdio.h>
#include<stdlib.h>
int penalty_shoot(char* s){
int count=0,i=0;
while(s[i]!='\0'){
if(s[i]=='2')
if(s[i+1]=='1')
count++;
i++;
}
return count;
}
int main() {
int t;
int i=0;
scanf("%d",&t); //t is for number of test cases.
while(t--){
char *str, c;
str = (char*)malloc(1*sizeof(char));
while(c = getc(stdin),c!='\n')
{
str[i] = c;
i++;
str=realloc(str,i*sizeof(char));
}
str[i] ='\0';
printf("%s\n",str);
printf("%d\n",penalty_shoot(str));
free(str);
str=NULL;
i=0;
}
return 0;
}
Input is :
3
101201212110
10101
2120
I am facing 2 problems:
1) I feel the dynamic allocation is not working fine.I wrote the code for dynamic allocation seeing various codes on stackoverflow . (Can anyone suggest some changes.)
2) The code isn't reading '2120' as the 3rd input.
(why is it so ?)
Three errors:
Not checking for EOF:
Change while(c = getc(stdin),c!='\n') to while(c=getc(stdin),c!='\n'&&c!=EOF)
Reallocating with the wrong number of bytes:
Change str=realloc(str,i*sizeof(char)); to str=realloc(str,(i+1)*sizeof(char));
After taking one character input we increment i (i++), so the next character will be stored at the ith position. Now, in order to store the character at ith position, the length of the character array must be i+1. So, we realloc with i+1.
Just for the sake of brevity, as suggested by Basile, you
might as well do this:
Change str=realloc(str,(i+1)*sizeof(char)); to str=realloc(str,i+1);
Why? Because sizeof char is 1 byte
Not consuming the \n after inputting t:
Change scanf("%d",&t); to scanf("%d ",&t); or scanf("%d\n",&t);
scanf("%d ",&t); or scanf("%d\n",&t);.
Either of them works. Why, you ask? Read this explanation taken from another SO answer here:
An \n - or any whitespace character - in the format string consumes
an entire (possibly empty) sequence of whitespace characters in the
input. So the scanf only returns when it encounters the next
non-whitespace character, or the end of the input stream.
Tested here.
you can use scanf("%d ", &t); when user input to test
then just before second while loop, which condition should be c != '\n' write c = getchar();
and then make sure you create a char variable, i called mine clear, that receives 0 so when you loop after initiating your string you write c = clear; and under it c = getchar() again. and when you use realloc make sure you make it bigger by (i+1) since char is only the size of 1 byte.
we create the clear variable in order to clear the buffer.
it worked for me. make sure you insert the string all at once.

Using strstr to determine if a given string contains a string with spaces [C]

I'm working through an example of using the strstr() function.
If I input "Pamela Sue Smith", why does the program output ""Pamela" is a sub-string!" and not ""Pamela Sue Smith" is a sub-string!".
#include <stdio.h>
#include <string.h>
void main(void)
{
char str[72];
char target[] = "Pamela Sue Smith";
printf("Enter your string: ");
scanf("%s", str);
if (strstr( target, str) != NULL )
printf(" %s is a sub-string!\n", str);
}
main does not have return-type void but int.
scanf can fail. Check the return-value.
If successful, it returns the number of parameters assigned.
%s only reads non-whitespace, until the next whitespace (thus 1 word).
%s does not limit how many non-whitespace characters are read. A buffer-overflow can be deadly.
Use %71s (buffer-size: string-length + 1 for the terminator)
You swapped the arguments to strstr.
From the manual page for scanf:
“s” — Matches a sequence of non-white-space characters; the next
pointer must be a pointer to character array that is long enough
to hold the input sequence and the terminating null byte ('\0'),
which is added automatically. The input string stops at white
space or at the maximum field width, whichever occurs first.
So, the part “Sue Smith” never makes it to str. You could use fgets which allows you to read a whole line at a time:
if (fgets(str, sizeof str, stdin) == NULL) {
printf("End of file\n");
return;
}
Note that in this case, str contains the terminating end-of-line character. You could do
if (*str != '\0')
str[strlen(str) - 1] = '\0';
to remove it.
(Also, as some others already pointed out, the “haystack” argument to strstr goes first.)

Resources