What's wrong with strtol? - c

I have this code, which should run fine, but for some reason, the loop would cycle through when I free the string before the conditional check of the loop. And the only way to get out from the loop is by giving integer with more than 3 digits (input > 99 || input < -99).
I'm using gcc to compile this code with code::blocks as IDE.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* createString(void);
int main() {
int temp = 0;
char* string = 0;
char* error = 0;
do {
printf("\n Integer: ");
string = createString();
temp = strtol(string, &error, 10);
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
free(string);
string = 0;
} while (*error != '\n' && *error != '\0');
free(error);
error = 0;
return 0;
}
char* createString() {
char* string = 0;
size_t size = 0;
size_t index = 0;
int ch = EOF;
do {
ch = getc(stdin);
if (ch == EOF || ch == '\n') ch = 0;
if (size <= index) string = (char*) realloc(string, size += 5);
if (!string) {
perror("realloc");
exit(EXIT_FAILURE);
}
string[index++] = ch;
} while(ch);
return string;
}
I did a work-around it by moving the free-ing process to the beginning of the loop cycle and after the loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* createString(void);
int main() {
int temp = 0;
char* string = 0;
char* error = 0;
do {
free(string);
string = 0;
printf("\n Integer: ");
string = createString();
temp = strtol(string, &error, 10);
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
} while (*error != '\n' && *error != '\0');
free(string);
string = 0;
free(error);
error = 0;
return 0;
}
char* createString() {
char* string = 0;
size_t size = 0;
size_t index = 0;
int ch = EOF;
do {
ch = getc(stdin);
if (ch == EOF || ch == '\n') ch = 0;
if (size <= index) string = (char*) realloc(string, size += 5);
if (!string) {
perror("realloc");
exit(EXIT_FAILURE);
}
string[index++] = ch;
} while(ch);
return string;
}
The code works fine now, but I'm wondering what is strtol doing.

free(error);
Remove it. error is not allocated in strtol or anywhere else. It is a pointer that points to the middle of string. Freeing it is UB.

You say:
for some reason, the loop would cycle through when I free the string before the conditional check of the loop
Keep in mind that with the call strtol(string, &error, 10); the pointer error will point into the string string. So if you free string before doing this:
if (*error != '\n' && *error != '\0') printf("\n Input is not an integer");
or this:
while (*error != '\n' && *error != '\0')
You'll invoke undefined behavior because error will be pointing to freed memory.

Related

Memory leak caused by realloc in valgrind C

I have a my_string object made that contains a char pointer, a size, and a capacity. I am trying to read words from a dictionary text file into the my_string object and print them to the screen. The default capacity is 7, so when I read a word that is longer than 7 characters, I need to reallocate some space at the end of the string. I haven't been able to implement this functionality correctly yet. It seems to work correctly, but when I run it in valgrind, there is apparently a memory leak somewhere in my code. Not sure where this is coming from, because I free the entire string after the program runs. If someone could help me with this you'd be a lifesaver. Here is my driver code, and my my_string.c file:
main.c
#include <stdio.h>
#include <stdlib.h>
#include "my_string.h"
int main(int argc, char* argv[]) {
MY_STRING hMy_String = NULL;
FILE* fp;
hMy_String = my_string_init_default();
fp = fopen("dictionary.txt", "r");
int len;
while(my_string_extraction(hMy_String, fp)) {
len = my_string_get_size(hMy_String);
if(len == 8){
my_string_insertion(hMy_String, stdout);
printf("\n");
if(fgetc(fp) == ' '){
printf("Found a space after the string\n");
}
}
}
my_string_destroy(&hMy_String);
fclose(fp);
return 0;
}
my_string.c
#include <stdio.h>
#include <stdlib.h>
#include "my_string.h"
struct my_string {
int size;
int capacity;
char* data;
};
typedef struct my_string My_String;
MY_STRING my_string_init_default(void){
//default capacity of string is 7
//initializes pointer to My_String, set to NULL for good practice
My_String* pMy_String = NULL;
//allocates memory for default string
pMy_String = (My_String*)malloc(sizeof(My_String));
if(pMy_String != NULL) {
pMy_String->size = 0;
pMy_String->capacity = 7;
pMy_String->data = (char*)malloc(sizeof(char) * pMy_String->capacity);
if(pMy_String->data == NULL) {
free(pMy_String);
pMy_String = NULL;
}
}
//returns copy of address to default string
return pMy_String;
}
MY_STRING my_string_init_c_string(char* c_string) {
int i = 0;
//initializes a pointer to a My_String
My_String* theString = NULL;
//loops through string, for every character, i increases 1
while((*c_string) != '\0'){
c_string++;
i++;
}
//resets c_strings value from before the loop
c_string = c_string - i;
i++; //i needs to be 1 greater than the length of the string
//allocation
theString = malloc(sizeof(My_String) + i);
//if there was an error, return NULL
if(theString == NULL)
return NULL;
else {
//sets the values of the object to the given values
(*theString).size = (i - 1);
(*theString).capacity = i;
(*theString).data = c_string;
}
//returns address of the initialized string
return theString;
}
int my_string_get_capacity(MY_STRING hMy_string){
return sizeof(hMy_string);
}
int my_string_get_size(MY_STRING hMy_string) {
char* str = (char*) hMy_string;
int size = 0;
while(str[size] != '\0')
size++;
return size;
}
int my_string_compare(MY_STRING hLeft_string, MY_STRING hRight_string) {
// sets the strings to pointers to the My_String data type
My_String* Left = hLeft_string;
My_String* Right = hRight_string;
//variables for lexicographical value of each string
int left_lex = 0;
int right_lex = 0;
//loops through left string, adds up left_lex value
while((*Left->data) != '\0') {
left_lex += (*Left->data);
(*Left).data++;
}
//loops through right string, adds up right_lex value
while((*Right->data) != '\0') {
right_lex += (*Right->data);
(*Right).data++;
}
//does the comparison and returns the corrosponding value
if(left_lex < right_lex){
return -1;
}else if (left_lex == right_lex) {
return 0;
}else {
return 1;
}
}
Status my_string_extraction(MY_STRING hMy_string, FILE* fp) {
My_String* pMy_string = hMy_string;
int start = 0, end = 0;
char ch;
int strLength, capacity, i;
while(!feof(fp)){
ch = fgetc(fp);
if(ch == ' ' || ch == '\t' || ch == '\n' ||ch == '\r') {
continue;
}
else {
start = ftell(fp) - 1;
end = start + 1;
break;
}
}
if(end == 0){
return FAILURE;
}
while(!feof(fp)) {
ch = fgetc(fp);
end++;
if(ch == ' ' || ch == '\t' || ch == '\n' ||ch == '\r'){
break;
}
}
strLength = end - start - 1;
(*pMy_string).size = strLength;
if(strLength == 0){
return FAILURE;
}
capacity = my_string_get_capacity(hMy_string);
if(strLength >= capacity){
hMy_string = realloc(hMy_string, strLength + 1);
}
fseek(fp, start, SEEK_SET);
char* str = (char*)hMy_string;
for(i = 0; i < strLength; i++) {
str[i] = fgetc(fp);
}
str[i] = '\0';
return SUCCESS;
}
Status my_string_insertion(MY_STRING hMy_string, FILE* fp) {
char* str = (char*)hMy_string;
if(fprintf(fp, "%s", str))
return SUCCESS;
else
return FAILURE;
}
void my_string_destroy(MY_STRING* phMy_string){
free(*phMy_string);
*phMy_string = NULL;
}

problems with pointers to copy characters

I have problems with getstring. I do not know why it does not work, the output in the main function printf do not put nothing
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *getstring(unsigned int len_max)
{
char *linePtr = malloc(len_max + 1); // Reserve storage for "worst case."
if (linePtr == NULL) { return NULL; }
int c = 0;
unsigned int i = 0;
while (i < len_max && (c = getchar()) != '\n' && c != EOF){
*linePtr++ = (char)c;
i++;
}
*linePtr = '\0';
return linePtr;
}
int main()
{
char *line = getstring(10);
printf("%s", line);
free(line);
return 0;
}
The problem is that linePtr points to the end of the string containing the input line, not the beginning, because you do linePtr++ during the loop.
Instead of incrementing linePtr, use linePtr[i++] to store each character during the loop.
char *getstring(unsigned int len_max)
{
char *linePtr = malloc(len_max + 1); // Reserve storage for "worst case."
if (linePtr == NULL) { return NULL; }
int c = 0;
unsigned int i = 0;
while (i < len_max && (c = getchar()) != '\n' && c != EOF){
linePtr[i++] = (char)c;
}
linePtr[i] = '\0';
return linePtr;
}
If you really need to do it by incrementing a pointer, you need to save the original value of linePtr in another variable, and return that rather than the one that you increment.
your problem is that you are returning the end of your buffer, You need to keep a copy of linePtr or to index it. (You are incrementing it in your loop);

K&R Exercise 1-19: Reverse Char Array

I'm able to reverse the array fine, but I can't get the program to terminate when I do CTRL+D(EOF) in terminal.
The only way I can get the program to terminate is if the very first thing I do after compiling is doing CTRL+D. But if I type in one string, then CTRL+D will not work after that.
I'm not quite sure where my error is.
#include <stdio.h>
#define MAXLINE 1000 // Maximum input.
// ----------------- reverseLine -----------------
// This method reads in chars to be put into an
// array to make a string. EOF and \n are the
// delimiters on the chars, then \0 is the
// delimiter for the string itself. Then the
// array is swapped in place to give the reverse
// of the string.
//------------------------------------------------
int reverseLine(char s[], int lim)
{
int c, i, newL;
// c is the individual chars, and i is for indices of the array.
for (i = 0; i < lim - 1 && (c=getchar()) != EOF && c != '\n'; ++i)
{
s[i] = c;
}
if (c == '\n') // This lets me know if the text ended in a new line.
{
newL = 1;
}
// REVERSE
int toSwap;
int end = i-1;
int begin = 0;
while(begin <= end) // Swap the array in place starting from both ends.
{
toSwap = s[begin];
s[begin] = s[end];
s[end] = toSwap;
--end;
++begin;
}
if (newL == 1) // Add the new line if it's there.
{
s[i] = '\n';
++i;
}
s[i] = '\0'; // Terminate the string.
return i;
}
int main()
{
int len;
char line[MAXLINE];
while ((len = reverseLine(line, MAXLINE)) > 0) // If len is zero, then there is no line to recored.
{
printf("%s", line);
}
return 0;
}
The only thing I can think of is the while loop in main checks if len > 0, so if I type EOF, maybe it can't make a valid comparison? But that wouldn't make sense as to why it works when that's the first and only thing I type.
Your program will never read the EOF because of this condition:
(c=getchar()) != EOF && c != '\n';
As soon as c is equal to '\n' the loop terminates and all the following characters are ignored. I think you should separate input from line reversing and make the usual checks on the reverse function parameters.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_MAX (256U)
static bool linereverse(char *line);
static bool deletenewline(char *s);
int main(void)
{
char buff[SIZE_MAX];
bool success;
(void) fputs("Enter a string: ", stdout);
if( NULL == fgets(buff,(size_t) SIZE_MAX, stdin))
{
(void) fputs("Error: invalid input!\n",stderr);
return EXIT_FAILURE;
}
success = deletenewline(buff);
if(false == success)
{
(void) fputs("Error: cannot remove newline\n",stderr);
return EXIT_FAILURE;
}
success = linereverse(buff);
if(false == success)
{
(void) fputs("Error: cannot reverse the line");
return EXIT_FAILURE;
}
(void) fputs("The line reversed is: ", stdout);
(void) fputs(buff, stdout);
(void) puchar('\n');
return EXIT_SUCCESS;
}
static bool linereverse(char *line)
{
size_t i;
size_t j;
char tmp;
if(NULL == line)
{
return false;
}
i = 0;
j = strlen(line) - 1;
while(i < j)
{
tmp = line[i];
line[i] = line[j];
line[j] tmp;
++i;
--j;
}
return true;
}
static bool deletenewline(char *s)
{
char *p;
if(NULL == s)
{
return false;
}
p = strrchr(s,'\n');
if(NULL != p)
{
*p = '\0';
}
return true;
}

filling a Char array with scanf in C

How can I fill an empty Char Array with keyboard?
something like
char a_string[];
while("if not Q")
{
printf("Enter a number: ");
scanf("%c", a_string);
}
I know this is wrong
I just want to know how to give values to my a_string[], without limiting the size.
so the size will vary depend on how many keys i'm gonna enter from keyboard.
Thanks!
If you will know at the start of runtime how many keys you'll enter, you can have it ask first for the number of keys and then for the individual characters, as in the untested snippet below.
Otherwise, you have to set some real-world maximum (e.g. 10000) that will never be reached, or, if that's not possible, set a per-array maximum and make provisions for rollover into a new array. That last option really is the same (eventually bounded by memory) but gives you a larger maximum.
char *mychars;
int numchars;
printf("Please enter the total number of characters:\n");
if (scanf("%d", &numchars) == NULL) {
printf("couldn't read the input; exiting\n");
exit(EXIT_FAILURE);
}
if (numchars <= 0) {
printf("this input must be positive; exiting\n");
exit(EXIT_FAILURE);
}
mychars = (char *) malloc (numchars * sizeof(char));
int current_pos = 0;
printf("Enter a digit and hit return:\n");
while (scanf("%c", &mychars[current_pos]) != NULL && current_pos < numchars) {
current_pos++;
printf("Enter a digit and hit return:\n");
}
Try this:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *string = NULL;
char *newstring = NULL;
char c = '\0';
unsigned int count = 0;
while(c != 'Q'){
c = getc(stdin);
if(string == NULL){
string = (char *) malloc(sizeof(char)); // remember to include stdlib.h
string[0] = c;
}
else{
newstring = (char *) realloc(string, sizeof(char)*count);
string = newstring;
string[count] = c;
}
count++;
}
string[count-1] = '\0'; // remove the Q character
fprintf(stderr,"here you are: %s",string);
free(string); // remember this!
return 0;
}
Repetitive calls to realloc() will meet the need.
Double realloc() size as needed to avoid O(n) calls.
char *GetQLessString(void) {
size_t size_alloc = 1;
size_t size_used = size_alloc;
char *a_string = malloc(size_alloc);
if (a_string == NULL) {
return NULL; // Out of memory
}
char ch;
while(scanf("%c", &ch) == 1 && (ch != 'Q')) {
size_used++;
if (size_used > size_alloc) {
if (size_alloc > SIZE_MAX/2) {
free(a_string);
return NULL; // Too big - been typing a long time
}
size_alloc *= 2;
char *new_str = realloc(a_string, size_alloc);
if (new_str == NULL) {
free(a_string);
return NULL; // Out of memory
}
a_string = new_str;
}
a_string[size_used - 2] = ch;
}
a_string[size_used - 1] = '\0';
return a_string;
}
Code could do a final realloc(a_string, size_used) to trim excess memory allocation.
Calling routine needs to call free() when done with the buffer.
The following would be cleaner.
int ch;
while((ch = fgetc(stdin)) != EOF && (ch != 'Q')) {

fgetc read file line by line

So I'm working on a function that will use fgetc to read a line into a buffer. so I can use that buffer as I please, and then refill the buffer with the next line. My function works however I have to repeat code outside of the for loop to process the last line as shown here:
for(i = 0, c = 1; ch != EOF; i++)
{
ch = fgetc(grab);
if(ch == 0x0A)
{
/*Process Line*/
c = 1;
}
else
{
linetmp = realloc(line, (c + 1) * sizeof(char));
if(!linetmp)
{
free(line);
free(url);
printf("\nError! Memory allocation failed!");
return 1;
}
line = linetmp;
line[c - 1] = ch;
line[c] = 0x00;
c++;
}
}
/*repeat if(ch == 0x0A) statement*/
I would rather do this all in the same loop but am not sure on how I would go about doing this. Any help would be greatly appreciated!
I would recommend that you instead use getline() if you're on a POSIX system.
Also, your logic is strange since you check for EOF in the loop header only, but update ch inside the loop. That means it will run through with ch == EOF, before the loop condition is re-evaluated.
You should try putting the updating and the check together, making the loop header read like this:
for(i = 0, c = 1; (ch = fgetc()) != EOF; i++)
Also, you need to think about line separators, both '\n' (carriage return) and '\n' (line feed) can occur.
I don't think you should reallocate after each character. If you want to have the buffer at the smallest value needed, you could reallocate at the end with ( strlen() + 1); Also, there is a function fgets() which reads a line.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int somefunc(FILE *grab)
{
int current_size = 100;
int data_size = current_size - 1;
char *url = malloc(current_size);
char *line = malloc(current_size);
char *linetmp;
int ch;
ch = fgetc(grab);
int i = 0;
int c = 0;
while (ch != EOF && ch != 0x0A )
{
i++;
if ( i > data_size )
{
current_size = current_size * 2;
data_size = current_size - 1;
linetmp = realloc(line, current_size);
if (!linetmp)
{
free(line);
free(url);
printf("\nError! Memory allocation failed!");
return 1;
}
line = linetmp;
}
line[c] = ch;
c++;
ch = fgetc(grab);
}
line[c] = '\0';
linetmp = realloc(line,strlen(line) + 1);
line = linetmp;
printf("we just read line->%s\n",line);
free(line);
free(url);
return 0;
}
int main(void)
{
char *cpFilename = "somefile.txt";
FILE *fp = fopen(cpFilename,"r");
if ( fp == NULL )
{
printf("ERROR: could not open %s\n",cpFilename);
printf("Error code: %d\n",errno);
perror("ERROR:");
return 1;
}
int return_code = somefunc(fp);
while (return_code != EOF && return_code != 1)
{
return_code = somefunc(fp);
}
fclose(fp);
}

Resources