Kochan InsertString segmentation fault - c

I am working through Kochan's programming in C book and I am working on an exercise which requires a function to insert one character string inside another string, with the function call including where the string is to be inserted.
I have written the below code but I receive a segmentation fault whenever I enter the inputs. I think it's because the 'input' string is defined to the length of the user's input and then the insertString function tries to add additional characters to this string. I just can't see a way of defining the string as large enough to be able to take in additional characters. Do you think that this is the reason I am receiving a segmentation fault? Are there any other ways to go about this problem?
#include<stdio.h>
#include <string.h>
insertString(char input[], const char insert[], int position)
{
int i, j;
char temp[81];
j = strlen(input);
for(i = 0; i < position - 1; i++)
{
temp[i] = input[i];
}
for(j = 0; insert != '\0'; i++, j++)
{
temp[i] = insert[j];
}
for(j = i - j; input != '\0'; i++, j++)
{
temp[i] = input[j];
}
for(i = 0; temp[i] != '\0'; i++)
{
input[i] = temp[i];
}
input[i] = '\0';
}
void readLine(char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
int main(void)
{
char input[81];
char insert[81];
int position;
printf("Enter the first string: ");
readLine(input);
printf("Enter the insert string: ");
readLine(insert);
printf("Enter placement position int: ");
scanf("%i", &position);
insertString(input, insert, position);
printf("The adjusted string is %s\n", input);
return 0;
}

There might be other reasons as well, but the following fragment will crash for sure:
for(j = 0; insert != '\0'; i++, j++)
{
temp[i] = insert[j];
}
The reason is that - since insert will not be increased or manipulated - this is an endless loop writing "indefinitely" long into temp. Once exceeding its length 80 (or a bit later) it will crash. I suppose you meant for(j = 0; insert[j] != '\0'; i++, j++), right?

Check all for loop conditions in insertString function. For example:
for(j = 0; insert != '\0'; i++, j++)
{
temp[i] = insert[j];
}
is infinite loop. Because of it you access memory out of temp array bounds. It causes UB and segmentation fault. Looks like you need insert[j] != '\0' condition here.

I'm familiar with this book. The author, Stephen Kochan, has a website with answers to the odd-numbered end of chapter exercises.
The website is at classroomm.com but you'll need to look around some to find the information.
Here is the info from that site related to this exercise:
Programming in C, exercise 10-7 (3rd edition) and 9-7 (4th edition)
/* insert string s into string source starting at i
This function uses the stringLength function defined
in the chapter.
Note: this function assumes source is big enough
to store the inserted string (dangerous!) */
void insertString (char source[], char s[], int i)
{
int j, lenS, lenSource;
/* first, find out how big the two strings are */
lenSource = stringLength (source);
lenS = stringLength (s);
/* sanity check here -- note that i == lenSource
effectively concatenates s onto the end of source */
if (i > lenSource)
return;
/* now we have to move the characters in source
down from the insertion point to make room for s.
Note that we copy the string starting from the end
to avoid overwriting characters in source.
We also copy the terminating null (j starts at lenS)
as well since the final result must be null-terminated */
for ( j = lenSource; j >= i; --j )
source [lenS + j] = source [j];
/* we've made room, now copy s into source at the
insertion point */
for ( j = 0; j < lenS; ++j )
source [j + i] = s[j];
}

There's an error somewhere in your insertString function where it goes out of bounds. By the way your insertString function doesn't start with the word void.
If I substitute the insertString function which I wrote for the exercise then the program works.
#include<stdio.h>
#include <string.h>
void insertString (char source[], const char s[], int start)
{
int stringLength (const char s[]);
int lenSource = strlen (source);
int lenString = strlen (s);
int i;
if ( start > lenSource ) {
printf ("insertion point exceeds string length\n");
return;
}
// move the characters in the source string which are above the
// starting point (including the terminating null character) to make
// room for the new characters; to avoid overwriting characters the
// process begins at the end of the string
for ( i = lenSource; i >= start; --i )
source[i + lenString] = source[i];
// insert new characters
for ( i = 0; i < lenString; ++i )
source[start + i] = s[i];
}
void readLine(char buffer[])
{
char character;
int i = 0;
do
{
character = getchar();
buffer[i] = character;
i++;
}
while(character != '\n');
buffer[i - 1] = '\0';
}
int main(void)
{
char input[81];
char insert[81];
int position;
printf("Enter the first string: ");
readLine(input);
printf("Enter the insert string: ");
readLine(insert);
printf("Enter placement position int: ");
scanf("%i", &position);
insertString(input, insert, position);
printf("The adjusted string is %s\n", input);
return 0;
}

Related

Trying to remove characters of string B from string A in standard C

So if A="aBcDeFg" and B="BDF", the output should be "aceg".
My idea was to check one-by-one if character of A is equal with any character of B (A[0] vs B[0]/B[1]...B[n] and so on). Therefore if they do not match, a counter variable is incremented. If the counter is smaller than length of B, then this character is deleted and when the counter equals length of B, the character is moved in an other string.
My version looks like this, but is not working:
void remove_characters(char s[], char r[])
{
int k, i, j, l = 0;
char s_copy[20];
for (i = 0; s[i] != '\0'; i++){
for (j = 0; r[j] != '\0'; j++)
if (s[i] != r[j])
k++;
if (k = strlen(r)){
s_copy[l++] = s[i];
k = 0;
}
}
puts(s_copy);
}
void main()
{
char s1[20],s2[20];
printf("Enter the first string: ");
gets(s1);
printf("Enter the second string: ");
gets(s2);
remove_characters(s1,s2);
}
Any ideas where is the problem?
Any ideas where is the problem?
There's more than one.
UnholySheep mentioned if (k = strlen(r)); you meant == rather than =.
k is not initialized before use; this is to be done before the inner loop.
s_copy is not null terminated.
Here's an alternative implementation which utilizes the standard function strchr and modifies s, which has the advantages that no limit is imposed on the length of s and that the result is available to the caller rather than just printed:
void remove_characters(char s[], char r[])
{
char *t = s;
do if (*s && strchr(r, *s)) continue;
else *t++ = *s;
while (*s++);
}

Create function which copy all values from one char array to another char array in C (segmentation fault)

I have a task. I must copy all values form one char array (sentence[]) to another empty char array sentence2[]), but I don't know why I get segmentation fault. They told us also that we must create own strlen function to check how long is string.
This is my code
#include <stdio.h>
#include <stdlib.h>
int new_strlen (char *tab)
{
int i;
for (i = 0; tab[i] != '\0'; ++i);
return i;
}
int copyText(char from[],char to[],int max)
{
int i, j;
if (new_strlen(from) <= max)
{
for(int i = 0; i != '\0'; i++) {
to[i] = from[i];
}
to[i+1] = '\0';
}
return 0;
}
int main (int argc, char *argv[])
{
char sentence[] = "C is \n a \n programming \t language";
char sentence2[1000];
copyText(sentence, sentence2, 1000);
printf("Show my array: %s \n", sentence2);
return 0;
}
Here are the bugs:
int copyText(char from[],char to[],int max)
{
int i, j; // minor problem: j is useless
if (new_strlen(from) <= max) // should be < instead of <=
{
for(int i = 0; i != '\0'; i++) { // here you declare a new i variable
// unrelated to the i declared at the beginning
to[i] = from[i];
}
to[i+1] = '\0'; // here you use again the i declared at the beginning
// which hasn't been initialized
// and i already is the index of the terminator
// therefore it should be to[i]
}
return 0;
}
This line contains two errors:
for(int i = 0; i != '\0'; i++)
i != '\0' is equivalent to i != 0. Now youv'e probably realized your error. Actually you need to test if from[i] is 0.
to[i+1] = '\0' : here i has already been incremented by the for loop, i already contains the index of the \0 terminator, therefore it should be to[i] = '\0'
And finally in this line you use the i variable declard at the beginning o the function whose content is indeterminate as you have never assigned anything to it and it is most likely this line that causes the segmentation fault: to[i+1] = '\0';
Finally there is another problem that will cause problems if the length of the string is max:
if (new_strlen(from) <= max) // should be < instead of <=
If the length of the string is max, then \0 will be put one beyond the end of the buffer, hence a buffer overflow.
You want this:
int copyText(char from[],char to[],int max)
{
if (new_strlen(from) < max)
{
int i;
for(i = 0; from[i] != '\0'; i++)
to[i] = from[i];
}
to[i] = '\0';
}
return 0;
}
Three issues with copyText
i != '\0' should be from[i] != '\0'
int i = 0 should be just i = 0 in for loop to not shadow the other i and also pointless to do it.
to[i+1] should be just to[i]
I modify my program like you said.
My program
#include <stdio.h>
#include <stdlib.h>
int new_strlen (char *tab)
{
int i;
for (i = 0; tab[i] != '\0'; ++i);
return i;
}
int copyText(char from[],char to[],int max)
{
if (new_strlen(from) < max)
{
int i;
for(int i = 0; from[i] != '\0'; i++)
{
to[i] = from[i];
}
to[i] = '\0';
}
return 0;
}
int main (int argc, char *argv[])
{
char sentence[] = "C is \n a \n programming \t language";
char sentence2[30];
copyText(sentence, sentence2, 30);
printf("Show my array: %s \n", sentence2);
return 0;
}
The output
Show my array: h�ܙ�
Why my output is wrong?
I sloved your problem. You just missed 'form[i]' in for loop of copytext() funtion. And used (new_strlen(from) <= max) instead (new_strlen(from) < max). And removed to[i+1] = '\0'; which was not needed.
#include <stdio.h>
#include <stdlib.h>
int new_strlen (char *tab)
{
int i;
for (i = 0; tab[i] != '\0'; ++i);
return i;
}
int copyText(char from[],char to[],int max)
{
if (new_strlen(from) <= max)
{
for(int i = 0; from[i] != '\0'; i++)
{
to[i] = from[i];
}
}
return 0;
}
int main (int argc, char *argv[])
{
char sentence[] = "C is \n a \n programming \t language";
char sentence2[1000];
copyText(sentence, sentence2, 1000);
printf("Show my array: %s \n", sentence2);
return 0;
}
I have a task. I must copy all values form one char array
(sentence[]) to another empty char array sentence2[]),
I you must copy all values then the third parameter of the function copyText
int copyText(char from[],char to[],int max);
is redundant. In general it does allow to copy all values.
I think that by "all values" you mean all characters of a string stored in the source array.
To copy a string from one character array to another character array the function that calculates the length of the string is not required. It is also redundant.
The return type int of the function copyText does not make a sense. The character array from which the stored string is copied shall have the qualifier const.
Standard C string functions follow the convention that the destination character array should be the first function parameter and functions should return pointer to the destination character array.
Within the function the declared variable j is not used
int i, j;
The reason of the segmentation fault is that you are using the non-initialized variable i to set the terminating zero character in the destination array. That is you declared an uninitialized variable i
int i, j;
then in the if statement in its inner loop
if (new_strlen(from) <= max)
{
for(int i = 0; i != '\0'; i++) {
^^^^^^^^^
to[i] = from[i];
}
to[i+1] = '\0';
}
you declared one more variable i which will not be alive outside the loop. The loop itself iterates never because the condition of the loop
i != '\0'
is not satisfied. The variable i was initialized by 0 and is compared with the same 0 that is written as an octal character literal.
So in this statement
to[i+1] = '\0';
there is used the initialized variable i declared in the beginning of the function before the if statement.
I am sure what you are required to write is an analog of ths atndard C function strcpy.
In this case the program can look the following way
#include <stdio.h>
char * copyText( char to[], const char from[] )
{
for ( char *p = to; ( *p++ = *from++ ) != 0; ) { /* empty */ }
return to;
}
int main (void)
{
enum { N = 1000 };
char sentence[] = "C is \n a \n programming \t language";
char sentence2[N];
printf("Show my array: %s \n", copyText(sentence2, sentence ) );
return 0;
}
The program output is
Show my array: C is
a
programming language

Why is my program to reverse its input a line at a time not working?

I was trying to write a program that reverses its input a line at a time. I thought I had done it successfully, however it sometimes doesn't give the desirable output (this happens when I put an input with a smaller length than the one I put previously). I am new to this and I was wondering what can I do to solve this issue.
Program:
#include <stdio.h>
#define MAXLINE 1000
void reverse(char o[], char l[]);
int mgetline(char line[]);
int main(void){
int len;
char line[MAXLINE];
char rev[MAXLINE];
while((len = mgetline(line)) > 0){
reverse(rev, line);
printf("%s\n",rev);
}
return 0;
}
int mgetline(char s[])
{
int c,i;
for(i = 0; ((c=getchar())!=EOF) && (c!='\n'); ++i)
s[i] = c;
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
void reverse(char revi[], char liner[])
{
int i, c, j;
for(i=0;liner[i]!='\0';++i)
;
--i;
if(liner[i]=='\n')
--i;
for(j=0; j<=i ; ++j){
c = i - j;
revi[j] = liner[c];
}
--j;
}
Since you not terminating the revi string at the end, therefore it will print the leftout characters from the previous result if the new input is smaller. Fix it by adding this
revi[j] = '\0';
at the end of the reverse function and delete that last --j;.
The function reverse does not build a string that is it does not append the terminating zero '\0' to the result string.
The second parameter of the function should have the qualifier const because it is not changed in the function.
As all standard C string functions this function should return pointer to the result string.
And it is better to name the function like reverse_copy instead of reverse because the name reverse is usually used when a container is reversed "in place".
It can look the following way
char * reverse_copy( char revi[], const char liner[] )
{
size_t n = 0;
while ( liner[n] ) ++n;
if ( n != 0 && liner[n-1] == '\n' ) --n;
size_t i = 0;
while ( n != 0 ) revi[i++] = liner[--n];
revi[i] = '\0';
return revi;
}

How to find number of times that a given word occurs in a sentence [C code]?

Here is my code. I need to find out the number of times a given word(a short string) occurs in a sentence(a long string).
Sample Input: the
the cat sat on the mat
Sample Output: 2
For some reason the string compare function is not working and my output is coming as zero. Kindly ignore the comments in the code as they have been put to debug the code.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(){
char word[50];
gets(word);
int len = strlen(word);
//printf("%d",len);
char nword[len];
char s[100];
strcpy(nword,word);
puts(nword);
printf("\n");
gets(s);
//printf("%d",strlen(s));
char a[50][50];
int i,j,k;
j = 0;
for(i=0;i<strlen(s);i++)
{
a[i][j] = s[i];
printf("%c",a[i][j]);
if(s[i] == ' ')
{
j++;
printf("\n");
}
}
printf("%d",j);
k = j;
//printf("\nk assigned\n");
j = 0;
//printf("j equal to zero\n");
int count = 0;
int temp = 0;
//printf("count initialized.\n");
for(i=0;i<k;i++)
{
if(strcmp(a[i],nword) == 0)
count++;
}
printf("\n%d",count);
return 0;
}
Your main problem is with this loop for numerous reasons
int i,j,k;
j = 0;
for(i=0;i<strlen(s);i++)
{
a[i][j] = s[i];
printf("%c",a[i][j]);
if(s[i] == ' ')
{
j++;
printf("\n");
}
}
Firstly you've got your indexes into a backwards - a[i][j] means the i-th string and the j-th character, but since you're incrementing j for each word you want it the other way around - a[j][i].
Secondly you can't use i for both indexing into s and a. Think about what happens when you are building the second string. In your example input the second word starts when i is 4 so the first character will be stored as a[1][4]=s[4] which leaves a[1][0] to a[1][3] uninitialised. So you have to use a 3rd variable to track where you are in the other string.
When you hit a space, you don't want to add it to your word as it won't match later on. You also need to add in a null-terminator character to the end of each string or else your code won't know where the end of the string is.
Putting the above together gives you something like this:
int i,j,k;
k = j = 0;
for(i=0;i<strlen(s);i++)
{
if(s[i] == ' ')
{
a[j][k] = '\0';
j++;
k=0;
printf("\n");
}
else
{
a[j][k] = s[i];
printf("%c",a[j][k]);
k++;
}
}
a[j][k]='\0';
The problem is that a is a two-dimentional array and you reference it as a one dimention. Maby you use a 2-dimentional array to represent i=line, j=character. If you keep this idea then you'll have to do this:
j=0;
for(i=0;i<k;i++)
{
if(strcmp(a[i][j],nword) == 0)
count++;
j++;
}
But then it will be difficult to detect words that are split in half. I'd recommend keeping a as a one dimentional array. Copy the contents of s[i] serially and when you want to distinguish lines use the \r\n operator.
I think you use your 2-dimensional array wrong. a[0][j] should be the first word from s[i]. But what you are doing is a[i][0] = s[i] which makes no sense to me.
Best regards
I would implement this using the functions strtok() and strcmp():
int main(void)
{
char word[] = "the"; /* the word you want to count*/
char sample[] = "the cat sat on the mat"; /* the string in which you want to count*/
char delimiters[] = " ,;.";
int counter;
char* currentWordPtr;
/* tokenize the string */
currentWordPtr = strtok(sample, delimiters);
while(currentWordPtr != NULL)
{
if(strcmp(word, currentWordPtr) == 0)
{
counter++;
}
/* get the next token (word) */
currentWordPtr = strtok(NULL, delimiters);
}
printf("Number of occurences of \"%s\" is %i\n", word, counter);
return 0;
}

Longest Substring Palindrome issue

I feel like I've got it almost down, but for some reason my second test is coming up with a shorter palindrome instead of the longest one. I've marked where I feel the error may be coming from, but at this point I'm kind of at a loss. Any direction would be appreciated!
#include <stdio.h>
#include <string.h>
/*
* Checks whether the characters from position first to position last of the string str form a palindrome.
* If it is palindrome it returns 1. Otherwise it returns 0.
*/
int isPalindrome(int first, int last, char *str)
{
int i;
for(i = first; i <= last; i++){
if(str[i] != str[last-i]){
return 0;
}
}
return 1;
}
/*
* Find and print the largest palindrome found in the string str. Uses isPalindrome as a helper function.
*/
void largestPalindrome(char *str)
{
int i, last, pStart, pEnd;
pStart = 0;
pEnd = 0;
int result;
for(i = 0; i < strlen(str); i++){
for(last = strlen(str); last >= i; last--){
result = isPalindrome(i, last, str);
//Possible error area
if(result == 1 && ((last-i)>(pEnd-pStart))){
pStart = i;
pEnd = last;
}
}
}
printf("Largest palindrome: ");
for(i = pStart; i <= pEnd; i++)
printf("%c", str[i]);
return;
}
/*
* Do not modify this code.
*/
int main(void)
{
int i = 0;
/* you can change these strings to other test cases but please change them back before submitting your code */
//str1 working correctly
char *str1 = "ABCBACDCBAAB";
char *str2 = "ABCBAHELLOHOWRACECARAREYOUIAMAIDOINEVERODDOREVENNGGOOD";
/* test easy example */
printf("Test String 1: %s\n",str1);
largestPalindrome(str1);
/* test hard example */
printf("\nTest String 2: %s\n",str2);
largestPalindrome(str2);
return 0;
}
Your code in isPalindrome doesn't work properly unless first is 0.
Consider isPalindrome(6, 10, "abcdefghhgX"):
i = 6;
last - i = 4;
comparing str[i] (aka str[6] aka 'g') with str[last-i] (aka str[4] aka 'e') is comparing data outside the range that is supposed to be under consideration.
It should be comparing with str[10] (or perhaps str[9] — depending on whether last is the index of the final character or one beyond the final character).
You need to revisit that code. Note, too, that your code will test each pair of characters twice where once is sufficient. I'd probably use two index variables, i and j, set to first and last. The loop would increment i and decrement j, and only continue while i is less than j.
for (int i = first, j = last; i < j; i++, j--)
{
if (str[i] != str[j])
return 0;
}
return 1;
In isPalindrome, replace the line if(str[i] != str[last-i]){ with if(str[i] != str[first+last-i]){.
Here's your problem:
for(i = first; i <= last; i++){
if(str[i] != str[last-i]){
return 0;
}
}
Should be:
for(i = first; i <= last; i++, last--){
if(str[i] != str[last]){
return 0;
}
}
Also, this:
for(last = strlen(str); last >= i; last--){
Should be:
for(last = strlen(str) - 1; last >= i; last--){

Resources