I am trying to pass strings (lines of text file) into arrays (array for f1 and array2 for f2). When I just print the buffer buffer2, the lines come up just fine. When I try to pass them using strcpy the program crashes with no apparent reason. I have tried the following:
Using a two dimensional array with no avail
Working with methods and tried to return char and THEN pass it to the array, so I can avoid this sloppy code, but this will do for now.
I am using windows 7 x64, with DEV-C++.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *arrayF1[20] ;
char *arrayF2[20] ;
int i = 0;
int size = 1024, pos;
int c;
int lineCount = 0;
char *buffer = (char *)malloc(size);
char *buffer2 = (char *)malloc(size);
char *array[100];
char *array2[100];
if (argc!=3)
{
printf("\nCommand Usage %s filename.txt filename.txt\n", argv[0]);
}
else
{
FILE *f1 = fopen(argv[1], "r");
FILE *f2 = fopen(argv[2], "r");
if(f1)
{
do { // read all lines in file
pos = 0;
do{ // read one line
c = fgetc(f1);
if(c != EOF) buffer[pos++] = (char)c;
if(pos >= size - 1) { // increase buffer length - leave room for 0
size *=2;
buffer = (char*)realloc(buffer, size);
}
}while(c != EOF && c != '\n');
lineCount++;
buffer[pos] = 0;
// line is now in buffer
strcpy(array[i], buffer);
printf("%s", array[i]);
//printf("%s", buffer);
i++;
} while(c != EOF);
printf("\n");
fclose(f1);
}
printf("%d\n",lineCount);
free(buffer);
lineCount=0;
i=0;
if (f2)
{
do { // read all lines in file
pos = 0;
do{ // read one line
c = fgetc(f2);
if(c != EOF) buffer2[pos++] = (char)c;
if(pos >= size - 1) { // increase buffer length - leave room for 0
size *=2;
buffer2 = (char*)realloc(buffer, size);
}
}while(c != EOF && c != '\n');
lineCount++;
buffer2[pos] = 0;
// line is now in buffer
strcpy(array2[i], buffer);
//printf("%s", buffer2);
printf("%s", array2[i]);
i++;
} while(c != EOF);
printf("\n");
fclose(f2);
}
printf("%d\n",lineCount);
free(buffer2);
}//end first else
return 0;
}
You haven't allocated any memory for the arrays in array. You'll need to do that before you can copy the strings there.
array[i] = malloc(pos + 1);
if (array[i] == NULL) {
// handle error
}
strcpy(array[i], buffer);
printf("%s", array[i]);
To strcpy() to a char*, you need to have already allocated memory for it. You can do this by making static char arrays:
char array[100][50]; //Strings can hold up to 50 chars
or you can use pointers and dynamically allocate them instead.
char *array[100];
for(int i = 0; i < 100; i++)
array[i] = malloc(sizeof(char) * 50); //Up to 50 chars
...
for(int i = 0; i < 100; i++)
free(array[i]); //Delete when you're finished
After allocating it with one of those methods, it's safe to write to it with strcpy().
Looks to me like you allocated the arrays on the stack but failed to ensure that they'd be big enough, since each has size exactly 100. Since you don't know how big they'll be, you can either allocate them dynamically (using #JohnKugelman's solution) or wait to declare them until after you know what their sizes need to be (i.e., how long the strings are that they need to hold).
the program crashes with no apparent reason
There is always a reason :)
This line:
char *array[100];
Creates an array of 100 pointers to characters.
Then this line:
strcpy(array[i], buffer);
Tries to copy your buffer to the ith pointer. The problem is that you never allocated any memory to those pointers, so strcpy() crashes. Just this:
array[i] = malloc(strlen(buffer)+1);
strcpy(array[i], buffer);
will resolve that error.
Related
I am trying to solve a problem on Dynamic memory allocation by reading the input from a file by malloc(),free(),realloc(); i just need help to push the strings into an array from the file, without the commas . My test.txt file are as follows:
a,5,0
a,25,1
a,1,2
r,10,1,3
f,2
int i;
int count;
char line[256];
char *str[20];//to store the strings without commas
char ch[20];
int main (void)
{
FILE *stream;
if ( (stream = fopen ( "test.txt", "r" )) == NULL )
{ printf ("Cannot read the new file\n");
exit (1);
}
while(fgets(line, sizeof line, stream))
{
printf ("%s", line);
int length = strlen(line);
strcpy(ch,line);
for (i=0;i<length;i++)
{
if (ch[i] != ',')
{
printf ("%c", ch[i]);
}
}
}
//i++;
//FREE(x);
//FREE(y);
//FREE(z);
fclose (stream);
the str[] array should only store values like a520. (excluding the commas)
First of all DO NOT use global variables unless it is absolutely requires.
I am assuming you want str as array of pointers and str[0] stores first line, str[1] stores second line and so on.
For this:
int line_pos = 0; //stores line_number
int char_pos = 0; //stores position in str[line_pos]
while(fgets(line, sizeof(line), stream))
{
printf ("%s", line);
int length = strlen(line);
strcpy(ch,line);
str[line_pos] = calloc(length, sizeof(char)); //allocating memory
for (i=0;i<length;i++)
{
if (ch[i] != ',')
{
*(str[line_pos]+char_pos) = ch[i]; //setting value of str[line][pos]
char_pos++;
}
}
char_pos = 0;
line_pos++;
}
printf("%s", str[0]); //print first line without comma
Note that it only works for 20 lines (because you declared *str[20]) and then for 21st or later lines it leads to overflow and can cause variety of disasters. You can include:
if (line_pos >= 20)
break;
as a safety measure.
Note that slighty more memory is allocated for str(memory allocated = memory_required + number of comma). To prevent this you can set ch to text without comma:
for (i=0;i<length;i++)
{
int j = 0; //stores position in ch
if (line[i] != ',')
{
ch[j++] = line[i];
}
Then allocate memory for str[line_pos] like:
str[line_pos] = calloc(strlen(ch0, sizeof(char));
I am given an assignment to take in and store a string using a function, however, I am given some restrictions.
Only able to use getchar() to take in user input character by character
No assumption of length of the input (Not allowed to create a array of size 100 for example)
Not allowed to read the input twice, for example, using the first round of input to count string size and then ask the user to input again after creating an array of the string's size that was counted on the first round.
Not allowed to create a large buffer so a constant size buffer means memory will be wasted if the input is 1 character for example
int read_string()
{
char* input;
int counter = 0;
while (( input = getchar()) != '\n') //read until detect '\n'
{
printf("%c\n",input);
counter = counter + 1;
}
printf("Length of string: %d\n", counter);
}
I currently have no idea how to store character by character and dynamically resize an "array" like vectors equivalent in C++. C does not have vectors based on my research.
Based on my code now, when i type in "Hello",
the output will be
h
e
l
l
o
but I do not know how to store each character in a dynamic array
You'd have to use the realloc function, if you want to dynamically increase the size with every new character that you read.
When you use realloc, the content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved to a new location. If the function fails to allocate the requested block of memory, a null pointer is returned.
For every character that I read, I increment buffsize, but I do allocate buffsize + 1. Why? Because I need one extra position for the NULL terminator.
The last free position for a letter would be buffsize - 1 in this case and the last one will be assigned at the end of the while loop.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
size_t buffsize = 0;
char *buffer = NULL;
char *temp;
char input;
while ((input = getchar()) != '\n') {
printf("%c\n", input);
/* Incraese the size & realloc */
++buffsize;
temp = realloc(buffer, (buffsize + 1) * sizeof(char));
if (!temp) {
printf("Error reallocating buffer!\n");
exit(1);
}
/* Setting the new read char */
buffer = temp;
buffer[buffsize - 1] = input;
}
if (buffsize) {
buffer[buffsize] = '\0';
printf("Result = [%s]\n", buffer);
} else {
printf("Empty input!\n");
}
printf("String size=%lu\n", buffsize);
/* Clean */
free(buffer);
return 0;
}
A bit more generic - function which adds a char to the string. Initially pointer should be NULL and it will take it into account automatically
char *addchar(char **str, int c)
{
size_t len= 0;
char *tmp;
if(*str)
{
len = strlen(*str);
}
tmp = realloc(*str, len + 2);
if(tmp)
{
*str = tmp;
tmp[len] = c;
tmp[len + 1] = 0;
}
return tmp;
}
and usage - a bit different than yours
int main()
{
char *mystring = NULL;
int input;
while (( input = getchar()) != EOF)
{
if(input == '\n' || input == '\r') continue;
if(!addchar(&mystring, input))
{
printf("\nMemory allocation error\n");
}
else
{
printf("String length %zu\n", strlen(mystring));
}
}
}
First off, the function getchar() returns and int not char * so you should not assign its return value to the pointer input declared in your code as char* input;
You should start by declaring an int variable; could be called len ; and initialize it with the value of 0. Next you should call the function malloc() and feed it 1 to allocate 1 byte of memory to hold a single character, and assign its return value to the pointer input, like the following:
int len = 0;
input = malloc(1);
Then you should store the NUL-terminating character '\0' in the allocated memory:
input[0] = '\0';
Then you create an int variable since the return value of getchar() is int. This variable which could be called ch shall store the user input.
Then you increase the size of your allocated storage to accommodate the new character:
input = realloc(input, len + 1);
input[len] = ch;
len++;
The entire code should look like the following:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int len = 0;
char *input = malloc(1);
input[0] = '\0';
int ch;
while ((ch = getchar()) != '\n')
{
input = realloc(input, len + 1);
input[len] = ch;
len++;
}
input[len] = '\0';
printf("You entered: %s\n", input);
printf("Length of str: %d\n", len);
free(input);
return 0;
}
Trying to read multiple line from file to store them in a structure made up of the string elements, however when I run the program it simply crashes and I haven't the faintest idea why.
function in question:
Hashtbl* loadfromfile(Hashtbl* hashtbl, char *path){
int i = 0;
char line[100];
char* string[40];
FILE *f = fopen(path, "r");
if(f == NULL){
printf("FILE NO FOUND!");
}else{
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
fclose(f);
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
for(i = 1; i<(SIZE*2); i++){
strcpy(hashtbl[i].value, string[i]);
i++;
}
return hashtbl;
}
}
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"
int main() {
Hashtbl* numbers;
numbers = init_hashtbl(); //init_hashtable initialises numbers
loadfromfile(numbers, "test.txt");
for(int i = 0; i<SIZE; i++) {
printf("%s1", numbers[i].subscript);
printf("%s2\n", numbers[i].value);
}
}
Hashtable structure:
typedef struct Hashtbls{
char *subscript;
char *value;
} Hashtbl;
init_hasthable function:
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = "ZERO";
hashtbl[i].value = "ZERO";
}
return hashtbl;
}
You have quite a few problems here:
if(f == NULL){
printf("FILE NO FOUND!");
}
If the file cannot be opened, then you cannot continue. Also the message might
be printed way later, use printf("FILE NOT FOUND!\n"); instead.
char* string[40];
...
while(fgets(line, sizeof(line), f)!=NULL){
strcpy(string[i],line);
i++;
}
string is an array of uninitialized pointers, you cannot write anything
there. You should do
while(fgets(line, sizeof line, f))
{
string[i] = malloc(strlen(line) + 1);
if(string[i] == NULL)
{
// error handling is needed
}
strcpy(string[i], line);
i++;
if(i == sizeof string / sizeof *string)
break;
}
// or if your system has strdup
while(fgets(line, sizeof line, f))
{
string[i] = strdup(line);
if(string[i] == NULL)
{
// error handling is needed
}
i++;
if(i == sizeof string / sizeof *string)
break;
}
Also you are not checking whether you read more than 40 lines. I did that with
the the last if. sizeof array / sizeof *array returns the number of
elements that an array can hold. Note that this only works for arrays, not
pointers, since in general sizeof array != sizeof pointer. Also don't forget
to free the allocated memory afterwards.
strcpy(hashtbl[i].subscript, string[i]);
...
strcpy(hashtbl[i].value, string[i]);
Are the subscript and value parameters here initialized in some way? Check
your init_hashtbl().
EDIT
Now that you posted init_hashtbl:
for(i = 0; i<(SIZE*2); i++){
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
You are initializing subscript and value with string literals, they
are pointing to read-only memory location, strcpy is going to fail. You have
to either allocate memory with malloc or change your structure with arrays.
Option 1
Keep the structure, change init_hashtbl
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
hashtbl[i].subscript = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].subscript, "ZERO");
hashtbl[i].value = malloc(SOME_MAXIMAL_LENGTH + 1);
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
You should always check the return value of malloc/calloc. Also the
problem here is that if you want to copy a string that is longer than
SOME_MAXIMAL_LENGTH, you are going to have a buffer overflow. So you should
use realloc in the reading routine:
for(i = 0; i<(SIZE*2); i++){
char *tmp = realloc(hashtbl[i].subscript, strlen(string[i]) + 1);
if(tmp == NULL)
{
// error handling
}
hashtbl[i].subscript = tmp;
strcpy(hashtbl[i].subscript, string[i]);
i++;
}
If you don't want to deal with realloc here, you have to make sure, that no
string[i] is longer than SOME_MAXIMAL_LENGTH.
Option 2
Change you structure and init:
typedef struct Hashtbls{
char subscript[SOME_MAXIMAL_LENGTH];
char value[SOME_MAXIMAL_LENGTH];
} Hashtbl;
Hashtbl* init_hashtbl(){
Hashtbl* hashtbl;
hashtbl = calloc(SIZE, sizeof(Hashtbl));
for(int i = 0; i<SIZE; i++){
strcpy(hashtbl[i].subscript, "ZERO");
strcpy(hashtbl[i].value, "ZERO");
}
return hashtbl;
}
Then in loadfromfile you don't have to deal with the realloc as shown
above, you can keep your code. However, you have to check that no string[i]
is longer than SOME_MAXIMAL_LENGTH - 1, otherwise buffer overflow.
One last thing, fgets reads a whole line, assuming that the length of the
line is lesser than sizeof line, the newline character will be added to the
line. You most likely don't want to have that. One way of getting rid of the
newline is:
fgets(line, sizeof line, f);
int len = strlen(line);
if(line[len - 1] == '\n')
line[len - 1] = 0;
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.
Hi im trying to read user input of "unlimited" length into an char array. It works fine for shorter strings, but for more than around 30 characters the programm crashes. Why does this happen and how can i fix this?
#include <stdio.h>
#include <stdlib.h>
char* read_string_from_terminal()//reads a string of variable length and returns a pointer to it
{
int length = 0; //counts number of characters
char c; //holds last read character
char *input;
input = (char *) malloc(sizeof(char)); //Allocate initial memory
if(input == NULL) //Fail if allocating of memory not possible
{
printf("Could not allocate memory!");
exit(EXIT_FAILURE);
}
while((c = getchar()) != '\n') //until end of line
{
realloc(input, (sizeof(char))); //allocate more memory
input[length++] = c; //save entered character
}
input[length] = '\0'; //add terminator
return input;
}
int main()
{
printf("Hello world!\n");
char* input;
printf("Input string, finish with Enter\n");
input = read_string_from_terminal();
printf("Output \n %s", input);
return EXIT_SUCCESS;
}
realloc(input, (sizeof(char))); //allocate more memory only allocates 1 char. Not 1 more char. #MikeCAT
(sizeof(char)*length+1) is semantically wrong. Should be (sizeof(char)*(length+1)), but since sizeof (char) == 1, it makes no functional difference.
Need space for the null character. #MikeCAT
Should test for reallocation failure.
char c is insufficient to distinguish all 257 different responses from getchar(). Use int. getchar() may return EOF. #Andrew Henle
Minor: Better to use size_t for array indexes than int. int maybe too narrow.
In the end code needs to do something like:
size_t length = 0;
char *input = malloc(1);
assert(input);
int c;
...
while((c = getchar()) != '\n' && c != EOF) {
char *t = realloc(input, length + 1);
assert(t);
input = t;
input[length++] = c;
}
...
return input;
int main(void) {
...
input = read_string_from_terminal();
printf("Output \n %s", input);
free(input);
return EXIT_SUCCESS;
}