Segmentation Fault when I add a for Loop - c

When I add the for loop I get segmentation fault. Also, when I add buffer[i] !='\0' in the while loop condition, I get segmentation fault error. I am having a hard time trying to understand why this error pops up. Thanks.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char buffer[2000] = "-rw-r--r-- 1 ftp ftp 614400 Oct 18 2006\r\n"
char String[2000];
int i, j, k= 0;
int nextline= 0;
for(k = 0; k<strlen(buffer);k++)
{
while((buffer[i] != '\r' && buffer[i+1] != '\n'))
{
String[j] = buffer[i];
i++;
j++;
}
}
printf("%s", String);
}

A loop of the form for(k=0; k < strlen(buffer); k++) { ... } is generally very bad code. It is O(n²), meaning that the time for the loop increases quadradically as n increases. Why? Each pass through the loop, the strlen function is called to determine the length of the string in buffer. If the string is 1000 character long, each strlen internally loops 1000 times, and it itself is called 1000 times, for 1000000 iterations of the inner loop! Instead, the length of the string should be calculated once, outside the loop. Eg)
int buffer_len = strlen(buffer);
for(k=0; k<buffer_len; k++) { ... }
You could also use a char * as your loop index, and loop until you encounter the null character:
for(char *c_ptr = buffer; *c_ptr != '\0'; *c_ptr++) { ... }
At any rate, for your problem, you do not need the double loop:
for(k = 0; k < strlen(buffer); k++)
{
// ...
while( /* incorrect condition here */ ) {
// ...
}
// ...
}
The above suggests you want to loop through each character in your string, and then starting at each of those characters, perform another inner loop. What you probably want is just an if( ) statement:
for(k = 0; k < strlen(buffer); k++)
{
// ...
if( buffer[k] == '\r' && buffer[k+1] == '\n' ) {
// ...
}
// ...
}
I'll leave you to struggle with what goes in the // ... comments, if anything. You learn more by doing.
As others have pointed out, your i & j variables were left uninitialized. You will want to ensure you initialize them properly before using them. You did initialize k to zero, which was actually unnecessary since the for(k=0; ... ; ...) loop is already initializing the value of k.

Related

Why I am getting a space character in my program in the place of third last character?

Why I am getting a space character in my program in the place of third last character?
Even if I change the string str variable I get the same result.
#include <stdio.h>
#include <string.h>
void parser(char array[])
{
int a, b;
for (int i = 0; i < strlen(array); i++) {
if (array[i] == '>') {
a = i;
break;
}
}
for (int j = a; j < strlen(array); j++) {
if (array[j] == '<') {
b = j;
}
}
for (int p = 0, q = a + 1; p < b - a - 1, q < b; p++, q++) {
array[p] = array[q];
array[b - a] = '\0';
printf("%c", array[p]);
}
}
int main()
{
char str[] = "<h1>hello there i am programmer.</h1>";
parser(str);
return 0;
}
There are many things that could be written better in the code but they do not affect the result.
The line that produces the unexpected outcome is:
array[b-a]='\0';
When this for loop starts...
for(int p=0,q=a+1;p<b-a-1,q<b;p++,q++){
array[p]=array[q];
array[b-a]='\0';
printf("%c",array[p]);
}
... the values of a and b are 3 and 32.
The statement array[b-a]='\0'; puts the NUL terminator character at position 29 in array.
The loop starts with p=0, q=4 (a+1) and repeats until p reaches 28 and q reaches 31 (q<b)*.
When p is 25, q is 29 and array[29] has been repeatedly set to '\0' on the previous iterations, therefore '\0' is copied at position 25 and printed on screen.
You should set the NUL terminator only once, after the loop. And the right position for it is b-a-1, not b-a; you expressed this correctly in the for initialization (p=0) and exit condition (p<b-a-1).
All in all, the code around the last for loop should be like this:
for(int p=0, q=a+1;q<b;p++,q++){
array[p]=array[q];
printf("%c",array[p]);
}
array[b-a-1]='\0';
*The condition p<b-a-1 is ignore because of the comma character. You probably want & between the conditions but they are equivalent, one of them is enough.

Remove vowels from a character string, Stack smashing error

#include <stdio.h>
#include <stdlib.h>
int main() {
char str[] = "my name is khan. and i am not a terrorist\n";
char arr[80];
char wolf[] = { 'a', 'e', 'i', 'o', 'u', '\0' };
int i, j, k, len;
len = strlen(str);
for (i = 0, j = 0; i < len; i++) {
for (k = 0; k <= 4; k++) {
if (wolf[k] != str[i]) {
arr[j] = str[i];
j++;
}
}
}
return 0;
}
Here, I have to remove vowels from string str. I am storing the resulting string in arr. But stack smashing error comes whenever I execute it. why?
What will happen when the char m is processed?
you will write it 5 times to arr. In general all chars will be written 4 or 5 times.
Don't write to arr in the inner-loop. Instead use a flag to remember whether you had a match. Test the flag after the loop to see if the char is to be written or not.
You have error in the check, you are copying the same characheter 5 times if the characheters is not vowel. you should make your check in this way
for(i=0,j=0;i<len;i++)
{
unsigned char isvowel = 0;
for(k=0;k<=4;k++)
{
if(wolf[k]==str[i])
{
isvowel = 1;
break;
}
}
if (!isvowel) {
arr[j]=str[i];
j++;
}
}
or you can develop a separate function to check if charachter is vowel:
unsigned char isvowel(char c)
{
char wolf[]={'a','e','i','o','u','\0'};
int k;
for(k=0;k<=4;k++)
{
if(wolf[k]==c)
{
return 1;
}
}
return 0;
}
And you can use it in your for loop in this way:
for(i=0,j=0;i<len;i++)
{
if (!isvowel(str[i]) {
arr[j]=str[i];
j++;
}
}
By the way, you have to add null charachter at the end of your arr string. After the for loop add the follwing line:
arr[j] = '\0';
You are getting a buffer overflow(probably) due to large number of comparisons being done. This part of your code:
if(wolf[k]!=str[i]){
arr[j]=str[i];
j++;
}
seems to change the value of j, every time there is a mismatch. For example lets say the first character 'm', will end up being copied more than once in your 'arr' array.
I modified your code a little change with a flag and at the end you missed arr[j]='\0';
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[]="my name is khan. and i am not a terrorist";
char arr[80]={0};
char wolf[]={'a','e','i','o','u','\0'};
int i,j,k,len,flag=0;
len=strlen(str);
for(i=0,j=0;i<len;i++)
{
for(k=0;k<=4;k++)
{
if(wolf[k]==str[i])
{
flag = 1;
break;
}
}
if(0==flag)
{
arr[j]=str[i];
j++;
}
flag=0;
}
arr[j]='\0';
printf("str:%s\n",str);
printf("arr:%s\n",arr);
return 0;
}
This may be the same idea of previous answers.
Stack smashing means you are using stack (a part of computer memory) illegally. This illegal use of stack memory can be done in many ways. One way do this is to add more elements to an array than its capacity. For example if you try to add 15 elements to an array with capacity of 10 elements then you will have stack smashing.
Here in your case, the array char arr[80]; has the capacity for 80 chars, but you are adding more than 80 chars in this array. This is why you are getting stack smashing error.
There are two issues in your code. First, you are adding elements from str[] more than one times to arr[].
/* Issue 1 */
for(k=0;k<=4;k++)
{
if(wolf[k]!=str[i])
{
/* You are adding str[i] to
arr[] multiple times
*/
arr[j]=str[i];
j++;
}
}
Here you are comparing str[i] with each vowel character and adding that character to arr[] everytime. This way each character is added 5 times (non-vowel characer), or 4 times (a vowel character).
To solve this issue, you need to compare str[i] with all vowels, and add it to arr[] only if it does NOT match to any vowel. There are many ways to do it. For example you can use an additional variable as a flag.
Second, you are not checking if there is any space left in arr[] to add any new character. In this part of your code:
/* Issue 2: You are not checking if space left in arr[] */
for(i=0,j=0;i<len;i++)
{
Here in your for loop condition you need to make sure that there is space left in arr[]. So, you need to add one more condition in your for loop.
This is one (among many) solutions:
/* Check if space left in arr, i.e. j < 80 */
for(i=0,j=0;i<len && j < 80;i++)
{
/* Add a flag:
1 means vowel
0 means not a vowel
*/
int v_flag = 0;
for(k=0;k<=4;k++)
{
if(wolf[k] == str[i])
{
v_flag = 1; /* Indicate that this is vowel */
break;
}
}
/* Add to arr[] only if not a vowel */
if (v_flag == 0)
{
arr[j] = str[i];
j++;
}
}
/* Null terminate the string */
arr[j] = '\0';
There are some string functions in the standard library that may help you, strchr() is one of them (you can get rid of the inner loop!) :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char str[] = "my name is khan. and i am not a terrorist\n";
char arr[80];
char *wolf = "aeiouy";
int i,j;
for(i=j=0; arr[j] = str[i]; i++)
{
if ( !strchr (wolf, str[i]) ) j++;
}
printf("%s\n", arr);
return 0;
}
You are actually duplicating the characters from str for each failed comparison to a vowel. The resulting string is between 4 and 5 times longer than the original, much longer than the destination array arr. Writing beyond the end of the array invokes undefined behavior: an early program termination in your case.
Here is how to fix your problem:
#include <stdio.h>
#include <stdlib.h>
int main() {
char str[] = "my name is khan. and i am not a terrorist\n";
char arr[80];
char wolf[] = { 'a', 'e', 'i', 'o', 'u', '\0' };
int i, j, k, len;
len = strlen(str);
for (i = 0, j = 0; i < len; i++) {
for (k = 0; k < 5; k++) {
if (str[i] == wolf[k])
break;
}
if (k == 5) { // not a vowel
arr[j] = str[i];
j++;
}
}
arr[j] = '\0'; // remember to put the final null byte to close the C string
printf("result: %s\n", arr);
return 0;
}

Deleting unused variable causes code to crash

So I'm trying to load the s-records from a .s19 file into memory for an assignment I'm working on, and its working. However, when I delete an unused array from my code, everything stops working and crashes.
The unused array is:
char test[65536];
And this is the loader I've written:
void loader(FILE * srec)
{
char instring[SREC_LEN];
char test[65536]; // This isn't used, but the program crashes without it for some reason
int i=0;
int j=0, k,l;
while (fgets(instring, SREC_LEN, srec) != NULL)
{
while(instring[i] != '\n') // Counts the characters in the s-record
{
i++;
}
j = j+i;
for(k=0;k<=i;k++) // Puts the records into memory
{
memory[l] = instring[k];
l++;
}
l = j;
}
#ifdef DEBUG
printf("MEMORY: %s",memory);
#endif // DEBUG
}
If you could help me to understand why this is happening, I would appreciate it.
Your code has undefined behavior, it only works by sheer luck:
fgets() may return without writing a newline character into the buffer if EOF is reached prematurely. So you should at least account for that in your loop. Also you never reset i to 0, which you should. Change this:
while(instring[i] != '\n') // Counts the characters in the s-record
{
i++;
}
to:
i = 0;
while(instring[i] != '\n' && instring[i] != '\0') // Counts the characters in the s-record
{
i++;
}
l is never initialized; you are probably writing out of bounds in memory. Initialize l to 0:
int j = 0, k, l = 0;
(I assume that memory is large enough to hold everything).
It also looks to me like you want for(k = 0; k < i; k++) rather than for(k = 0; k <= i; k++), since i is the count of characters you want to copy.
You might want to use memcpy() instead.

Using histogram to find the most common letter in an array

This is what I came up with, but I always get a Run-Time Check Failure #2 - Stack around the variable 'h' was corrupted.
int mostCommonLetter(char s[]) {
int i=0, h[26],k=0, max=0, number=0;
while ( k < 26){
h[k] = '0';
k++;
}
while(s[i] != '\0'){
h[whichLetter(s[i])] = h[whichLetter(s[i])]+1;
i++;
}
h[26] = '\0';
for(i=0;h[i]!='\0';i++){
if(h[i] > max)
number=i;
}
return number;
}
You cannot do h[26] = '\0'; - h has 26 elements indexed 0..25. As you know the length of h you don't need to 0-terminate it, simply do for (i=0; i < 26; ++i)
Also, are you certain whichLetter always returns a value in the 0..25 range? What does it do if it e.g. encounters a space?
This writes past the end of the array:
h[26] = '\0';
Make the for loop depend on the length rather than the last character:
for(i=0;i<26;i++){
if(h[i] > max)
number=i;
}

Segmentation fault using arrays

Well, I've been at this forever and I know exactly where the fault is, but no clue how to fix it. I already know fgets and scanf would be better for this program, but I can't do that.
The program worked about 10 minutes ago, then I changed it and got a seg fault. Then I changed it back and still got a seg fault. Anyway, I'm sure the fresh eyes will see it right away. Have at it :D
PS: Please note my (lessthan) instead of < because I don't know how to properly leave those in my code examples still :(
#define WORDLENGTH 15
#define MAXLINE 1000
int main()
{
char *line[MAXLINE];
int i = 0;
int j;
int n;
char c;
for (n=0; c!=EOF; n++){
char *tmp = (char *) malloc(sizeof(char)*WORDLENGTH);
while ((c=getchar())!=' ')
tmp[i++]=c;
line[n]=tmp;
i=0;
printf("\n%s\n",line[n]); //
}
for(j = 0; j < n; j++){
printf("\n%s\n", line[j]);
free (line[j]);
}
return 0;
}
you are doing line[n++] = tmp. And then accessing line[n] after that. But line[n] hasn't been assigned.
To change it, you can print line[n-1] instead, but clearer would be:
line[n] = tmp;
i = 0;
printf(... line[n]);
and place the increment in the for statement instead i.e. for (n = 0; c != EOF; n++).
EDIT
This is a summary of what I would do:
Place the i=0 assignment at the start of the loop. Logically, it is an initialization of i and currently it is done in two places (at int i = 0; and after the assignment of line[n]). Both places are not near where one would expect an initialization of a variable used in the while loop to be.
Guard against nonsense input by checking that i does not exceed WORDLENGTH-1. Actually, I would probably code the inner while loop as a for loop on i like so:
for (i = 0; i < WORDLENGTH; i++) {
tmp[i] = getchar();
if (tmp[i] == ' ') break;
}
tmp[i] = 0;
or (in my character) for(i = 0; i < WORDLENGTH; ++i) if ((tmp[i] = getchar()) == ' ') break; followed by..
tmp[i] = 0 to NUL-terminate the string. Since malloc doesn't necessarily return a 0-filled memory block.
there are still bugs in the suggested solution !
malloc() can fail and return a NULL pointer
at the end of the for () the maximum i value is WORDLENGTH
so this assignment isn't correct ( out of bounds )
tmp[i]= 0;
Can fix both with
char *tmp = (char *) malloc( sizeof(char) * (WORDLENGTH + 1) );
if ( tmp == NULL ) // end of available memory
break;
moreover, it isn't clear if you allow EOF inside the last string.

Resources