I am looking at problem 112 from UVa Online Judge.
For a couple of weeks ago, I got some homeworks from my university and the thing is that, though other problems are accepted on the UVa, I cannot figure out what is going wrong with this problem. I've already run the input from Udebug website and there was no problem. I double-checked the result and now, I'm sick and tired of solving this issue.
Here are details about what has happened. First of all, I increase the BUFSIZE to 2^20 in order to avoid any memory overflow. The result? Failed. Second, I downsized the size of the element in the stack I made. The result? Failed. Lastly, I removed an eol character of the result just in case. The result? Failed.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define BUFSIZE 16384
typedef struct node {
int element[BUFSIZE];
int size;
int current;
}Stack;//This is a stack I made
static Stack *stack;
static int level;//This is a level of a node in the whole tree
static int integer;//This is an integer that should be came out from the sum() function
bool initialize(void) {
if (stack == NULL)
stack = (Stack *)malloc(sizeof(Stack));
stack->size = BUFSIZE;
stack->current = 0;
return true;
}
bool push(int number) {
if (stack == NULL)
return false;
if ((stack->current + 1) > stack->size)
return false;
stack->element[stack->current] = number;
stack->current++;
return true;
}
int pop() {
if (stack->current <= 0)
return 0xFFFFFFFF;
stack->current--;
return stack->element[stack->current];
}
int sum() {
int result = 0;
int i;
if (stack == NULL)
return 0xFFFFFFFF;
if (stack->current == 0)
return 0xFFFFFFFF;
for (i = 0; i < stack->current; i++)
result += stack->element[i];
return result;
}//Sum all the values in the stack and return it.
void replace(char * o_string, char * s_string, char * r_string) {
char *buffer = (char *)calloc(BUFSIZE, sizeof(char));
char * ch;
if (!(ch = strstr(o_string, s_string)))
return;
strncpy(buffer, o_string, ch - o_string);
buffer[ch - o_string] = 0;
sprintf(buffer + (ch - o_string), "%s%s", r_string, ch + strlen(s_string));
o_string[0] = 0;
strcpy(o_string, buffer);
free(buffer);
return replace(o_string, s_string, r_string);
}//This is a function I found on Google. Memory usage optimization is not guaranteed.
int main(void) {
char *buffer;
char *line;
char *restOfTheString;
char *token;
bool checked = false, found = false;
int i = 0, j = 0, scannedInteger, result = 0, array[4096];
buffer = (char *)calloc(BUFSIZE, sizeof(char));
restOfTheString = (char *)calloc(BUFSIZE, sizeof(char));
line = (char *)calloc(BUFSIZE, sizeof(char));
memset(buffer, 0, BUFSIZE);
for (i = 0; i < 4096; i++) {
array[i] = -1;
}
level = 0;
integer = 0;
while (fgets(line, sizeof(line), stdin) != NULL) {//Get input line by line
if (line[0] != '\n') {
token = strtok(line, "\n");
if (strlen(line) >= 1) {
strcat(buffer, token);
}
}
}
replace(buffer, " ", "");
replace(buffer, "()()", "K");
strcpy(restOfTheString, buffer);
i = 0;
while (restOfTheString[i] != 0) {
if (level == 0 && !checked) {//If the level of the node is 0, then it is clearly the summed value I need to find out on the whole tree.
initialize();
sscanf(&restOfTheString[i], "%d%s", &integer, &restOfTheString[0]);
i = -1;
checked = true;
}
if (restOfTheString[i] == '(') {
checked = false;
level++;
}//If there is an openning bracket, then increase the level of the node.
else if (restOfTheString[i] == ')') {
if (restOfTheString[i - 1] != '(')
if (pop() == 0xFFFFFFFF)
return 0;
level--;
if (!found && level == 0) {
array[j] = 0;
j++;
free(stack);
stack = NULL;
}//If there is a closing bracket, then it's time to check whether the level of the node is 0. If the level of the node is 0, then we need to report the result to the 'array' which is an integer array and move on to the next input.
else if (found && level == 0) {
array[j] = 1;
j++;
free(stack);
stack = NULL;
found = false;
}
}
else if (restOfTheString[i] == '-' && !checked) {
if (sscanf(&restOfTheString[i], "%d%s", &scannedInteger, &restOfTheString[0]) == 2) {
if (push(scannedInteger) == false)
return 0;
i = -1;
}
}//If there is a minus character, then it's obvious that the next couple of characters are a negative integer and I need to scan it out of the whole input.
else if (restOfTheString[i] >= 48 && restOfTheString[i] <= 57 && !checked) {
if (sscanf(&restOfTheString[i], "%d%s", &scannedInteger, &restOfTheString[0]) == 2) {
if (push(scannedInteger) == false)
return 0;
i = -1;
}
}//If there is a numerous character, then it's obvious that the next couple of characters are a negative integer and I need to scan it out of the whole input.
else if (restOfTheString[i] == 'K') {
if ((result = sum()) == 0xFFFFFFFF)
return 0;
if (result == integer) {
found = true;
}
}//The 'K' character means the integer scanned prior to this iteration is a value in a leaf. So I need to call the sum() function in order to figure it out the result.
i++;
}
i = 0;
while (array[i] != -1) {
if (array[i] == 1)
printf("yes\n");
else if (array[i] == 0)
printf("no\n");
i++;
}
return 0;
}
Though it is clearly suspicious about the memory usage, I don't know how to track the stack on my system.
You use many questionable practices.
You free and re-allocate the stack from scratch. The stack has a fixed size in your case; allocate one at the beginning of main and free once at the end.
You set the index i to −1 as indicator, but keep on accessing restOfString[i] later. restOfString is an allocated string and writing to bytes before the actual data might corrupt the internal information that thze system keeps for allocated memory. This might lead to errors when freeing. In any case, it's undefined behaviour.
You read the input line-wise and concatenate everything into one huge string. You use strcat for this, which will get slower as your string grows. If you must load everything into a large buffer, consider using fread.
Your recursive replace method also does a lot of copying of temporarily allocated buffers.
This:
sscanf(&rest[i], "%d%s", &integer, &rest[0]);
looks fishy. You store the result in the string that you are reading, albeit at different indices. Result and source may overlap, which probably is undefined behaviour. In any case, it entails a lot of copying. Instead of using sscanf, you could read the integer with strtol, which gives you the position of the string after parsing the number. Continue scanning the old string at the resulting offset.
Your problems seem to be not in the core algorithm but with reading the input. Ihe assignment does not mention a maximum line length. This may be a sign that you shouldn't read the input in a line context.
You can use the scanf functions which don't know about line breaks. You can make use of the fact that unsuccessful scanning with data conversion, e.g. scanning an integer, resets the input stream.
Such a strategy would require only storage for the current token. You don't even need a stack if you use recursion. I doubt that the test cases in the online judge will break the stack limit, even if there they contain degenerate trees with a large depths.
Related
I need to write these two functions:
Precondition: hMy_string is the handle to a valid My_string object.
Postcondition: hMy_string will be the handle of a string object that contains
the next string from the file stream fp according to the following rules.
1) Leading whitespace will be ignored.
2) All characters (after the first non-whitespace character is obtained and included) will be added to the string until a stopping condition
is met. The capacity of the string will continue to grow as needed
until all characters are stored.
3) A stopping condition is met if we read a whitespace character after
we have read at least one non-whitespace character or if we reach
the end of the file.
Function will return SUCCESS if a non-empty string is read successfully.
and failure otherwise. Remember that the incoming string may aleady
contain some data and this function should replace the data but not
necessarily resize the array unless needed.
Status my_string_extraction(MY_STRING hMy_string, FILE* fp);
Precondition: hMy_string is the handle to a valid My_string object.
Postcondition: Writes the characters contained in the string object indicated by the handle hMy_string to the file stream fp.
Function will return SUCCESS if it successfully writes the string and
FAILURE otherwise.
Status my_string_insertion(MY_STRING hMy_string, FILE* fp);
However, I am getting a segmentation fault with my current code:
#include <stdio.h>
#include <stdlib.h>
#include "my_string.h"
Status my_string_extraction(MY_STRING hMy_string, FILE *fp)
{
string *pString = (string *) hMy_string;
int lws = 0;
int exit = 0;
int nws = 0;
int i;
int count = 0;
while(fp != NULL && exit == 0) {
if(pString->size >= pString->capacity) {
char *t_data = (char *)malloc(sizeof(char) * pString->capacity * 2);
if(t_data == NULL) {
return FAILURE;
}
for(i = 0; i < pString->size; i++) {
t_data[i] = pString->data[i];
}
free(pString->data);
pString->data = t_data;
pString->capacity *= 2;
if(getc(fp) == ' ' && lws == 0) {
lws++;
} else if(getc(fp) == ' ' && lws == 1) {
exit++;
} else if(getc(fp) == ' ' && nws > 0) {
exit++;
} else {
pString->data[count] = getc(fp);
count++;
pString->size++;
nws++;
}
fp++;
}
return SUCCESS;
}
Status my_string_insertion(MY_STRING hMy_string, FILE *fp)
{
int i;
string *pString = (string *) hMy_string;
for(i = 0; i < pString->size; i++) {
putc(pString->data[i], fp);
}
if(fp == NULL) {
return FAILURE;
}
return SUCCESS;
}
I am getting a segmentation fault with my current code
Why do you do this:
fp++; // incrementing pointer does not get you the next character in the file
When you try to get next character via getc(fp) that is enough to cause the crash . fp will be invalid pointer at that moment.
Also, I see no restrictions for crossing data boundary:
pString->data[count] = getc(fp);
count++; // count is not restricted from growing
I want to dynamically allocate only a portion of a character array.
So part of an array of size 100 is concrete. Say 10 is permanent memory, the other 90 is dynamic memory.
I made some attempt to read character by character until I decided to give up and take a shortcut idea I thought would work. However I end up getting an error that is
incorrect checksum for freed object - object was probably modified
after being freed
I use this method in a while loop in main and I pretty much free everything after the while loop processes. Because, I have the declaration outside of the while loop. I wanted to read an object in a while loop session since these objects end up being added into a list of objects. However the scope of the while loop causes segmentation problems, it cannot remember anything about the object. (I digress).
Here is my attempt.
Object* read(char* str)
{
Object* object = (Object*)malloc(sizeof(*object));
object->identity[0] = 0;
int capacity = (100 + 1) - (10);
object->name = (char*)malloc(capacity * sizeof(*object->name));
object->value = 0.0;
int length = strlen(str);
if (length > capacity)
object->name = (char*)realloc(object->name, (capacity * 2) * sizeof(*object->name));
int arguments = sscanf(str, "%" STRING_SPACE "s %lf %[^\n]s",
object->identity,
&object->value,
object->name);
if (arguments == MATCHER) {
return object;
} else {
return NULL;
}
return object;
}
In this case, an object has a variable sized name but a fixed amount of space allocated for its identity.
I tried something else with sscanf but realized it will never work because I read the string too late to assign memory to name. See;
/*
int len = 0;
for (char* itemObserve = item->name; *itemObserve; itemObserve++) {
if (len == sizeof(item->name)) {
capacity *= MULTIPLIER;
item->name = (char*)realloc(item->name, capacity * sizeof(*item->name));
}
len++;
}
*/
Here is the code in main, everything undefined is probably irrelevant to the bug:
int main()
{
FILE* stream;
Object* object;
ObjectList* list = initList();
while (true) {
char* line;
char cmd[15] = {0};
char* arg;
char* rest;
printf("> ");
line = getline(stdin);
arg = (char*)malloc(35 * sizeof(*arg));
rest = (char*)malloc(35 * sizeof(*rest));
int arguments = sscanf(line, "%s %s %[^\n]", cmd, arg, rest);
free(line);
line = NULL;
printf("\n");
if (strcmp(cmd, "add") == 0) {
arg = (char*)realloc(arg, (35 * 2) * sizeof(*arg));
sprintf(arg, "%s %s", arg, rest);
if ((object = read(arg)) == NULL) {
continue;
}
objectListAdd(list, object);
} else {
free(rest);
free(arg);
exit(EXIT_SUCCESS);
}
free(rest);
free(arg);
}
freeObject(object);
freeObjectList(list);
return EXIT_SUCCESS;
}
Separate getline function in main file
char* getline(FILE* stream)
{
int capacity = LINE_MAX + 1;
char* buffer = (char*)malloc(capacity * sizeof(*buffer));
int len = 0;
int ch;
while ((ch = fgetc(stream)) != '\n' && (ch != EOF)) {
if (len == capacity) {
capacity *= MULTIPLIER;
buffer = (char*)realloc(buffer, capacity * sizeof(*buffer));
}
buffer[len++] = ch;
}
if (ch == EOF) {
return NULL;
}
buffer[len] = '\0';
if (buffer == NULL)
return NULL;
return buffer;
}
There are other conditionals which work as a kind of command switch but they are irrelevant to the errors my program is exhibiting. This much I have narrowed the problem down to.
I am posed with a situation where my function does exactly what I want except handle higher amounts of input.
I initially thought to process each character one by one but was running into problems doing this. So fscanf not only does what I want it to do but it is essential in reading in only one line. I noticed, I cannot reallocate space for bigger array this way though. I have tried using format specifiers i.e. %*s to include a specific amount of buffer space before hand but this still does not work.
I have noticed also, I would have no way of knowing the size of the string I am reading in.
Here is my attempt and thoughts:
#define LINE_MAX 1000
char* getline(FILE* inputStream)
{
int capacity = LINE_MAX;
char* line = malloc(capacity * sizeof(char));
int ch;
/* if (sizeof(capacity) == sizeof(line)) { // Not a valid comparison? Too late?
capacity *= 2;
line = realloc(line, capacity * sizeof(line));
} */
if (fscanf(stream, "%[^\n]s", line) == 1) {
ch = fgetc(inputStream);
if (ch != '\n' && ch != EOF) {
fscanf(inputStream, "%*[^\n]");
fscanf(inputStream, "%*c");
}
free(line);
return line;
}
free(line);
return NULL;
}
I am new to memory allocation in general but I feel as though I had a good idea of what to do here. Turns out I was wrong.
Here is an example to read a line and store it in a Character array.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
signed char *str;
int c;
int i;
int size = 10;
str = malloc(size*sizeof(char));
for(i=0;(c=getchar()) !='\n' && c != EOF;++i){
if( i == size){
size = 2*size;
str = realloc(str, size*sizeof(char));
if(str == NULL){
printf("Error Unable to Grow String! :(");
exit(-1);
}
}
str[i] = c;
}
if(i == size){
str = realloc(str, (size+1)*sizeof(char));
if(str == NULL){
printf("Error Unable to Grow String! :(");
exit(-1);
}
}
str[i] = '\0';
printf("My String : %s", str);
return 0;
}
The array is resized to twice it's original size if current array can't hold the characters read from input.
I want to make a function that reads a line of your choice, from a given text file. Moving on to the function as parameters (int fd of the open, and int line_number)
It must do so using the language C and Unix system calls (read and / or open).
It should also read any spaces, and it must not have real limits (ie the line must be able to have a length of your choice).
The function I did is this:
char* read_line(int file, int numero_riga){
char myb[1];
if (numero_riga < 1) {
return NULL;
}
char* myb2 = malloc(sizeof(char)*100);
memset(myb2, 0, sizeof(char));
ssize_t n;
int i = 1;
while (i < numero_riga) {
if((n = read(file, myb, 1)) == -1){
perror("read fail");
exit(EXIT_FAILURE);
}
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
numero_riga++;
int j = 0;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return myb2;
}else{
myb2[j] = myb[0];
j++;
}
}
return myb2;
}
Until recently, I thought that this would work but it really has some problems.
Using message queues, the string read by the read_line is received as a void string ( "\0" ). I know the message queues are not the problem because trying to pass a normal string did not create the problem.
If possible I would like a fix with explanation of why I should correct it in a certain way. This is because if I do not understand my mistakes I risk repeating them in the future.
EDIT 1. Based upon the answers I decided to add some questions.
How do I end myb2? Can someone give me an example based on my code?
How do I know in advance the amount of characters that make up a line of txt to read?
EDIT 2. I don't know the number of char the line have so I don't know how many char to allocate; that's why I use *100.
Partial Analysis
You've got a memory leak at:
char* myb2 = (char*) malloc((sizeof(char*))*100);
memset(myb2, 0, sizeof(char));
if (numero_riga < 1) {
return NULL;
}
Check numero_riga before you allocate the memory.
The following loop is also dubious at best:
int i = 1;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
You don't check whether read() actually returned anything quick enough, and when you do check, you leak memory (again) and ignore anything that was read beforehand, and you don't detect errors (n < 0). When you do detect a newline, you simply add 1 to i. At no point do you save the character read in a buffer (such as myb2). All in all, that seem's pretty thoroughly broken…unless…unless you're trying to read the Nth line in the file from scratch, rather than the next line in the file, which is more usual.
What you need to be doing is:
scan N-1 lines, paying attention to EOF
while another byte is available
if it is newline, terminate the string and return it
otherwise, add it to the buffer, allocating space if there isn't room.
Implementation
I think I'd probably use a function get_ch() like this:
static inline int get_ch(int fd)
{
char c;
if (read(fd, &c, 1) == 1)
return (unsigned char)c;
return EOF;
}
Then in the main char *read_nth_line(int fd, int line_no) function you can do:
char *read_nth_line(int fd, int line_no)
{
if (line_no <= 0)
return NULL;
/* Skip preceding lines */
for (int i = 1; i < line_no; i++)
{
int c;
while ((c = get_ch(fd)) != '\n')
{
if (c == EOF)
return NULL;
}
}
/* Capture next line */
size_t max_len = 8;
size_t act_len = 0;
char *buffer = malloc(8);
int c;
while ((c = get_ch(fd)) != EOF && c != '\n')
{
if (act_len + 2 >= max_len)
{
size_t new_len = max_len * 2;
char *new_buf = realloc(buffer, new_len);
if (new_buf == 0)
{
free(buffer);
return NULL;
}
buffer = new_buf;
max_len = new_len;
}
buffer[act_len++] = c;
}
if (c == '\n')
buffer[act_len++] = c;
buffer[act_len] = '\0';
return buffer;
}
Test code added:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
extern char *read_nth_line(int fd, int line_no);
…code from main answer…
int main(void)
{
char *line;
while ((line = read_nth_line(0, 3)) != NULL)
{
printf("[[%s]]\n", line);
free(line);
}
return 0;
}
This reads every third line from standard input. It seems to work correctly. It would be a good idea to do more exhaustive checking of boundary conditions (short lines, etc) to make sure it doesn't abuse memory. (Testing lines of lengths 1 — newline only — up to 18 characters with valgrind shows it is OK. Random longer tests also seemed to be correct.)
I am doing an exercise for fun from K and R C programming book. The program is for finding the longest line from a set of lines entered by the user and then prints it.
Inputs:
This is a test
This is another long test
this is another long testthis is another long test
Observation:
It runs fine for the first two inputs but fails for the larger string (3rd input)
Errors:
Error in `./longest': realloc(): invalid next size: 0x000000000246e010 ***
Error in `./longest': malloc(): memory corruption (fast): 0x000000000246e030 ***
My efforts:
I have been trying to debug this since 2 days (rubber duck debugging) but the logic seems fine. GDB points to the realloc call in the _getline function and shows a huge backtrace with glibc.so memory allocation calls at the top.
Here is what I have written (partially, some part is taken from the book directly):-
#include <stdio.h>
#include <stdlib.h>
int MAXLINE = 10;
int INCREMENT = 10;
char* line = NULL, *longest = NULL;
void _memcleanup(){
free(line);
free(longest);
}
void copy(char longest[], char line[]){
int i=0;
char* temp = realloc(longest,(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
longest = temp;
while((longest[i] = line[i]) != '\0'){
++i;
}
}
int _getline(char s[]){
int i,c;
for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
if(i == MAXLINE - 1){
char* temp = realloc(s,(MAXLINE + INCREMENT)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
s= temp;
MAXLINE += INCREMENT;
}
s[i] = c;
}
if(c == '\n'){
s[i++] = c;
}
s[i]= '\0';
return i;
}
int main(){
int max=0, len;
line = malloc(MAXLINE*sizeof(char));
longest = malloc(MAXLINE*sizeof(char));
while((len = _getline(line)) > 0){
printf("%d%d", len, MAXLINE);
if(len > max){
max = len;
copy(longest, line);
}
}
if(max>0){
printf("%s",longest);
}
_memcleanup();
return 0;
}
You´re reallocating on copied addresses (because parameters).
A parameter in C is a copy of the original value everytime; in case of
a pointer it will point to the same location but the address itself is copied.
realloc resizes the buffer asociated with the address, everything fine so far.
But it can relocate the whole thing and assign a completely new address,
and this new address (if it happens) will be lost after the function returns to main.
Use a double pointer:
Pass a char **s instead of char *s (==char s[]) as formal parameter,
pass &xyz intead of xyz as actual value, and inside the function,
use *xyz and **xyz (or (*xyz)[index]) for address and value.
Other things:
Global variables are ugly (and confusing when named same as parameters),
multiplying with sizeof(char) is nonsense because it´s be 1 everytime,
and names in capitals should be used for #define´s rather than variables.
The double pointer alone, isn't the solution to your problems. You have 2 primary issues. You can see them by entering your strings as a string of characters and will notice you problem occurs when you pass the 20th character. (e.g. 01234567890123456789)
You have declared both line and longest globally. So while you can rewrite _getline (char **s), you can also simply update line at the end of _getline with memcpy (include string.h). For example:
memcpy (line, s, (size_t)i);
return i;
}
That cures your _getline issue. Issue two is fairly straight forward. You are not null-terminating longest in copy. (your choice of arguments with the same name as the globals presents challenges as well) Including the following fixes copy:
++i;
}
longest[i] = '\0';
}
If you incorporate both changes, then I believe you will find you routine works. You can then rewite _getline (char **s) and pass &line as another exercise. For example, you can rewrite _getline as:
int
_getline (char **s) {
int i, c;
for (i = 0; ((c = getchar ()) != EOF && c != '\n'); i++) {
if (i == MAXLINE - 1) {
char *temp = realloc (*s, (MAXLINE + INCREMENT) * sizeof (char));
if (temp == NULL) {
printf ("%s", "Unable to allocate memory");
_memcleanup ();
exit (1);
}
*s = temp;
MAXLINE += INCREMENT;
}
(*s)[i] = c;
}
if (c == '\n') {
(*s)[i++] = c;
}
(*s)[i] = '\0';
return i;
}
And then modify your call in main to:
while ((len = _getline (&line)) > 0) {