Deleting unused variable causes code to crash - c

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.

Related

Segmentation Fault when I add a for Loop

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.

Removing spaces from array input by user

I want to remove any spaces from the user input and give the result back on the screen. So far, the following is my working solution. I haven't noticed any errors yet. Since I'm pretty new to C and programming in general, my question is: Is there something I can do better? Anything to optimize or something? I appreciate any tips from you guys since you are probably a lot more experienced than I am. So, here's my code:
#include <stdio.h>
#include <string.h>
#define PUFFERGROESSE 100
#define ERROR 1
#define OK 0
int main(){
char stringPuffer[PUFFERGROESSE];
printf("Please enter some words:"); fflush(stdout);
if(fgets(stringPuffer, PUFFERGROESSE, stdin) == NULL){
printf("Unable to read.\n");
return ERROR;
} else {
char endString[PUFFERGROESSE];
for (int i = 0, j = 0; i < PUFFERGROESSE; i++, j++) {
if (stringPuffer[i] != ' ' ) {
endString[j] = stringPuffer[i];
} else {
j--;
}
}
printf("Without spaces your input looks like that: %s", endString);
}
}
In your code, the for loop condition is i < PUFFERGROESSE. Inside this loop, you access stringPuffer using the loop index.
Now, stringPuffer being an uninitialized automatic local variable and with a sufficiently small input, a strict check like i < PUFFERGROESSE will cause access to uninitialized memory of stringPuffer, creating undefined behavior.
You can make use of strlen() after taking the user input.
Another note, int main() is better as int main(void), at least.
NITPICK: why's the OK defined, if not used?
Several suggestions:
Initialize endString to all zeros; that way you won't have to worry about string termination issues later on:char endString[PUFFERGROESSE] = {0};
Instead of looping while i is less than PUFFERGROESSE, loop until you see the end of the string:for( int i = 0, j = 0; stringPuffer[i] != 0; i++ )
Also, only increment j when you write the non-space character, rather than incrementing it unconditionally and then having to decrement it when you see a space:if ( !isspace( stringPuffer[i] ) )
endString[j++] = stringPuffer[i];
So basically, that code reduces to:
char endString[PUFFERGROESSE] = {0};
for (int i = 0, j = 0; stringPuffer[i] != 0; i++) {
if ( !isspace( stringPuffer[i] ) ) {
endString[j++] = stringPuffer[i];
}
}

realloc() seems to affect already allocated memory

I am experiencing an issue where the invocation of realloc seems to modify the contents of another string, keyfile.
It's supposed to run through a null-terminated char* (keyfile), which contains just above 500 characters. The problem, however, is that the reallocation I perform in the while-loop seems to modify the contents of the keyfile.
I tried removing the dynamic reallocation with realloc and instead initialize the pointers in the for-loop with a size of 200*sizeof(int) instead. The problem remains, the keyfile string is modified during the (re)allocation of memory, and I have no idea why. I have confirmed this by printing the keyfile-string before and after both the malloc and realloc statements.
Note: The keyfile only contains the characters a-z, no digits, spaces, linebreaks or uppercase. Only a text of 26, lowercase letters.
int **getCharMap(const char *keyfile) {
char *alphabet = "abcdefghijklmnopqrstuvwxyz";
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++) {
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
}
int letter;
int count = 0;
unsigned char c = keyfile[count];
while (c != '\0') {
int arr_count = charmap[c][0];
arr_count++;
charmap[c] = realloc(charmap[c], (arr_count+1)*sizeof(int));
charmap[c][0] = arr_count;
charmap[c][arr_count] = count;
c = keyfile[++count];
}
// Just inspecting the results for debugging
printf("\nCHARMAP\n");
for (int i = 0; i < 26; i++) {
letter = (int) alphabet[i];
printf("%c: ", (char) letter);
int count = charmap[letter][0];
printf("%d", charmap[letter][0]);
if (count > 0) {
for (int j = 1; j < count+1; j++) {
printf(",%d", charmap[letter][j]);
}
}
printf("\n");
}
exit(0);
return charmap;
}
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
You are writing beyond the end of your charmap array. So, you are invoking undefined behaviour and it's not surprising that you are seeing weird effects.
You are using the character codes as an index into the array, but they do not start at 0! They start at whatever the ASCII code for a is.
You should use alphabet[i] - 'a' as your array index.
The following piece of code is a source of troubles:
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++)
charmap[...] = ...;
If sizeof(int) < sizeof(int*), then it will be performing illegal memory access operations.
For example, on 64-bit platforms, the case is usually sizeof(int) == 4 < 8 == sizeof(int*).
Under that scenario, by writing into charmap[13...25], you will be accessing unallocated memory.
Change this:
int **charmap = malloc(26*sizeof(int));
To this:
int **charmap = malloc(26*sizeof(int*));

Word Wrap Program C

At the end of Chapter 1 of The C Programming Language, there are a few exercises to complete. The one I am doing now asks you to make a program that wraps a long string of text into multiple lines at a specific length. The following function works 100%, aside from the last line which does not get wrapped, no matter the specified maximum width of a line.
// wrap: take a long input line and wrap it into multiple lines
void wrap(char s[], const int wrapline)
{
int i, k, wraploc, lastwrap;
lastwrap = 0; // saves character index after most recent line wrap
wraploc = 0; // used to find the location for next word wrap
for (i = 0; s[i] != '\0'; ++i, ++wraploc) {
if (wraploc >= wrapline) {
for (k = i; k > 0; --k) {
// make sure word wrap doesn't overflow past maximum length
if (k - lastwrap <= wrapline && s[k] == ' ') {
s[k] = '\n';
lastwrap = k+1;
break;
}
}
wraploc = 0;
}
} // end main loop
for (i = 0; i < wrapline; ++i) printf(" ");
printf("|\n");
printf("%s\n", s);
}
I have found the issue to be with the variable wraploc, which is incremented until it is greater than wrapline (the maximum index of a line). Once it is greater than wrapline, a newline is inserted at the appropriate location and wraploc is reset to 0.
The problem is that on the last line, wraploc is never greater than wrapline, even when it should be. It increments perfectly throughout iteration of the string, until the last line. Take this example:
char s[] = "This is a sample string the last line will surely overflow";
wrap(s, 15);
$ ./a.out
|
this is a
sample string
the last line
will surely overflow
The line represents the location where it should be wrapped. In this case, wraploc has the value 14, when there are clearly more characters than that.
I have no idea why this is happening, can someone help me out?
(Also I'm a complete beginner to C and I have no experience with pointers so please stay away from those in your answers, thanks).
You increment wraploc with i until it reaches wrapline (15 in the example).
When you wrap, you backtrack from i, back to the last whitespace.
That means that in your next line you already have some characters between the lastwrap location and i, i.e., you can't reset wraploc to 0 there.
Try setting wraploc = i-lastwrap instead.
Anybody who might, like me, find this question and run into a problem with new-lines in the source string.
This is my answer:
inline int wordlen(const char * str){
int tempindex=0;
while(str[tempindex]!=' ' && str[tempindex]!=0 && str[tempindex]!='\n'){
++tempindex;
}
return(tempindex);
}
void wrap(char * s, const int wrapline){
int index=0;
int curlinelen = 0;
while(s[index] != '\0'){
if(s[index] == '\n'){
curlinelen=0;
}
else if(s[index] == ' '){
if(curlinelen+wordlen(&s[index+1]) >= wrapline){
s[index] = '\n';
curlinelen = 0;
}
}
curlinelen++;
index++;
}
}

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