C issue with dynamically allocating array - c

The input file for my program has the first line containing an int (call it N) that will signify how many following integers there will be (each integer on a new line). Then it should read the integers into num_array and print them out. My issue is that num_array is not being allocated properly I think. The debugging statements in the code will print out 8 being the sizeof(num_array) no matter what N is.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int *num_array;
int main (int argc, char**argv){
int numThreads = (int) argv[1];
char *inputFile = argv[2];
int N = 0;
char line[20];
FILE *file = fopen(inputFile, "r");
int fileCounter = 0;
while(fgets(line, sizeof(line), file)) {
if (fileCounter==0){
N = atoi(line);
num_array = malloc(sizeof(int)*(N+1));
}
else{
num_array[fileCounter-1] = atoi(line);
}
fileCounter++;
}
fclose(file);
int i;
printf("%d", sizeof(num_array));
printf("\n");
printf("\n");
for(i = 0; i<sizeof(num_array); i++){
printf("%d\n", num_array[i]);
}
return 0;
}
Input file example:
9
10
9
3
212
56
99
4
5
6
will print out:
8
10
9
3
212
56
99
4
5
As you can see, the last element of the array is cut off (does not print 6) and it appears num_array is not being sized properly (should contain N integers with N being the int at the first line of the input file)

Many problems with your program:
The first line of your main() function has a very severe mistake
int numThreads = (int) argv[1]
in c casting does not convert the type, this conversion is certainly possible, but doesn't give the result you expect, you need something like this
char *endptr;
int numThreads = strtol(argv[1], &endptr, 10);
if (*endptr != '\0')
{
printf("`%s' cannot be converted to an integer\n", argv[1]);
return -1;
}
You didn't make sure that there was a parameter provided to your program's command line, you need to check that, argc contains the number of command line arguments passed to your program + the argv[0], so you must check
if (argc < 2)
{
printf("Use: %s NumberOfThreads, where NumberOfThreads is `int'\n", argv[0]);
return -1;
}
You don't check if fopen() returns NULL, that would cause more issues when you fgets() the file pointer.
The sizeof operator does not give the length of an array it gives the number of bytes occupied by the array, and you variable is not an array, it's a pointer, so the sizeof operator in this case is giving the size of a pointer.
It turns out that your file contains 9 values and in your platform the pointer size is 8, so sizeof(num_array) is 8 which is 9 - 1 hence your are missing one value, you already have the number of elements of the array N, so use it.
You never call free().
This is a version of your code, it's fixed and it's made safer
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int *num_array;
int main (int argc, char**argv)
{
char line[20];
/*int numThreads = 1;*/
char *inputFile = "data.dat";
int N = 0;
int fileCounter = 0;
int i = 0;
FILE *file = fopen(inputFile, "r");
if (file == NULL)
return -1;
while (fgets(line, sizeof(line), file) != NULL)
{
if (fileCounter == 0)
{
N = atoi(line);
num_array = malloc((1 + N) * sizeof(int));
if (num_array == NULL)
{
fclose(file);
return -1;
}
}
else
{
num_array[fileCounter - 1] = atoi(line);
}
fileCounter++;
}
fclose(file);
printf("%ld", sizeof(num_array));
printf("\n");
printf("\n");
for (i = 0 ; i < N ; i++)
{
printf("%d\n", num_array[i]);
}
free(num_array);
return 0;
}

Related

Reading file content line by line into a matrix

I was trying to write a function that could copy a text file content line by line to a matrix, so this is what I came up with:
#include <stdio.h>
#include <stdlib.h>
#define rows 5
#define columns 12
void file_to_matrix(char *matrix[]){
FILE *file = fopen("swamp.txt", "r");
if(file==NULL){
printf("File error");
exit(1);
}
int y=0;
for(int x=0; (matrix[y][x]=fgetc(file))!=EOF; ++x){
if(matrix[y][x]=='\n'){
++y;
x=0;
}
}
fclose(file);
}
int main(){
char *matrix[rows];
file_to_matrix(matrix);
for(int i=0; i<5; ++i){
for(int j = 0; j < 11; j++){
printf("%c", matrix[i][j]);
}
printf("\n");
}
}
I tried to compile and run it on Windows and Linux but the only thing that it manages to do is giving me errors that are practically useless like:
"Stopping due to fatal error: NullReferenceException: Object reference not set to an instance of an object"
or
"Segmentation fault (core dumped)"
You have to allocate memory for each element of matrix. This is the same exact mistake as writing:
char *s = "string";
As the first act of the program, loop through matrix, and call malloc for each cell:
int i;
for (i = 0; i < 5; ++i)
if (!(matrix[i] = malloc(MAXLEN))) [
perror("malloc");
exit(EXIT_FAILURE);
}
Note: we check the return value of malloc to ensure no errors have occurred.
with your code, i think the matrix in the file will restricted (you define rows=5 and columns=12). so i think again to write a code that can be flexible, no need to set max row or column again. here we go
#include <stdio.h>
#include <stdlib.h> //malloc realloc
//file read function. returning string with splitted new line
//ex: (note: newline is '\n' (ENTER))
//test.txt:
//10 20 30(space)(newline)
//40 50 60(space)(newline)
void file_to_matrix(char *filename)
{
FILE * file = fopen(filename, "r");
char *buff = (char*)malloc(sizeof(char)); //temp string
int *matrix_row = (int*)malloc(sizeof(int)); //temp matrix row
int **MATRIX = (int**)malloc(sizeof(int*)); //this will become the final matrix
int index_buff = 0, index_MATRIX = 0, index_matrix_row = 0;
while (1)
{
char c = getc(file);
if (c==EOF)
{
break;
}
if (c=='\n') //if c meet newline, then add the matrix row to final matrix
{
(*(MATRIX+index_MATRIX)) = matrix_row;
index_MATRIX++;
MATRIX = realloc(MATRIX, sizeof(MATRIX)*(index_MATRIX+1));
matrix_row = (int*)malloc(sizeof(int));
index_matrix_row = 0;
printf("\n");
continue;
}
if (c==' ') //if c meet space, then buff wil converted to int
{
int num = atoi(buff);
printf("%d ", num);
(*(matrix_row+index_matrix_row)) = num;
index_matrix_row++;
matrix_row = realloc(matrix_row, sizeof(int)*(index_matrix_row+1));
free(buff);
buff = (char*)malloc(sizeof(char));
index_buff=0;
continue;
}
//add buff with c
(*(buff+index_buff))=c;
index_buff++;
buff = realloc(buff, sizeof(char)*(index_buff+1));
}
fclose(file);
//clearing the dynamic memory
free(buff);
for (int i = 0; i < index_MATRIX; i++)
{
free(MATRIX[i]);
}
}
int main()
{
file_to_matrix("test.txt");
return 0;
}
test.txt:
10 20 30
40 50 60
70 80 90
if you confused with the test.txt format, i will explain again:
10 20 30(space)(newline)
30 40 60(space)(newline)
70 80 90(space)(newline)
Thank you for your replies, I think your solutions are very clever but I was looking to an easier one.
After a little bit of trial and error I think I found a solution that it isn't very generalized but it's simple and it seems to work fine:
#include <stdlib.h>
#include <stdio.h>
#define ROWS <n of rows>
#define COLS <n of columns>
void file_to_matrix(int rows, int cols, char matrix[rows][cols], char file_path[]){
FILE *file = fopen(file_path, "r");
if(file==NULL){
printf("File error");
exit(1);
}
int y=0;
for(int x=0; (matrix[y][x]=getc(file))!=EOF; ++x){
if(matrix[y][x]=='\n'){
matrix[y][x]='\0';
++y;
x=-1;
}
}
fclose(file);
}
int main(){
char matrix[ROWS][COLS+2];
file_to_matrix(ROWS, COLS+2, matrix, "file path");
for(int i=0; i<=ROWS; ++i){
printf("%s\n", matrix[i]);
}
}
Thank you again for your answers

Reading in Large Integer txt file into 2D array

Attempting to create a program that reasons in a large Text File and filled them into Rows + Columns. Eventually I'll have to computer best path but having trouble just implementing an Array that can store the values.
#include <stdio.h>
#include <stdlib.h>
//max number of characters to read in a line. //MAXN=5 means 4 chars are read, then a \0 added in fgets. See reference for functionality
#define MAXN 100L
int main(void) //char** argv also ok {
int i=0, totalNums, totalNum,j=0;
size_t count;
int numbers[100][100];
char *line = malloc(100);
FILE* inFile ;
inFile = fopen("Downloads/readTopoData/topo983by450.txt", "r"); //open a file from user for reading
if( inFile == NULL) { // should print out a reasonable message of failure here
printf("no bueno \n");
exit(1);
}
while(getline(&line,&count, inFile)!=-1) {
for(;count>0; count--,j++)
sscanf(line, "%d", &numbers[i][j]);
i++;
}
totalNums = i;
totalNum = j;
for(i=0;i<totalNums; i++){
for(j=0;j<totalNum;j++){
printf("\n%d", numbers[i][j]);
}
}
fclose(inFile);
return 0;
}
count does not tell you how many numbers there are. Further: sscanf(line, "%d", &numbers[i][j]); will just scan the same number every time.
So this
for(;count>0; count--,j++)
sscanf(line, "%d", &numbers[i][j]);
should be something like:
j = 0;
int x = 0;
int t;
while(sscanf(line + x, "%d%n", &numbers[i][j], &t) == 1)
{
x += t;
++j;
}
where x together with %n helps you move to a new position in the string when a number has been scanned.
Here is a simplified version that scans for numbers in a string:
#include <stdio.h>
int main(void) {
char line[] = "10 20 30 40";
int numbers[4];
int j = 0;
int x = 0;
int t;
while(j < 4 && sscanf(line + x, "%d%n", &numbers[j], &t) == 1)
{
x += t;
++j;
}
for(t=0; t<j; ++t) printf("%d\n", numbers[t]);
return 0;
}
Output:
10
20
30
40

How to turn an array from command line into an array of integers?

I'd like to know how I can turn arrays such as {33,44,77,88} or {10,20,30}, that are given given as command line arguments, and turn them from a char to an integer and finally put them into an array of integers.
I've been looking for hours and I cannot find an example where they get the array from the command line and turn it into an integer array.
This is what I had placed at the command line FOO {33,44,77,88} {10,20,30}
My first 4 lines look like this.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
Passing in command-line arguments will pass them in as strings and only strings. Therefore, your argv array will look like this: argv = {"./prog", "FOO", "{33,44,77,88}", "{10,20,30}"};. This means that your passed in array will need to be parsed by your program in order to convert it into an integer array. Try using functions like strtok to parse a string based on a delimiter. Then, once you get the individual numbers, i.e. you have parsed "33", you can use atoi to convert this string into an integer. You will need to build your array up manually.
The following code will interpret any arguments starting with '{' and pull any numbers out that are comma delimited.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
long int* processArray(char* input, int* lng){
int length = 0, i = 0;
while (input[i] != '\0'){
if (input[i] == ',') length ++;
i++;
}
if (length > 0) length ++;
input++;
int j = 0;
long int * out = malloc(length * sizeof(long int));
while(*input != '}'){
while(*input != '\0' && !isdigit(*input)) input++;
if (!isdigit(*input)) break;
out[j++] = strtol(input, &input, 10);
}
*lng = j;
return out;
}
int main(int argc, char ** argv){
int i;
for ( i = 0; i < argc; i++){
// check for variables that look like arrays
if (argv[i][0] == '{'){
printf("Processing '%s'\n", argv[i]);
int l, j;
long int * variables = processArray(argv[i], &l);
printf("Got Array: { ");
for (j = 0; j < l; j++){
printf("%ld%s", variables[j], j == l-1? "" : ", ");
}
printf(" }\n");
}
}
}
Sample output:
./array-args '{ 1, 2, 3 }'
Processing '{1, 2, 3}'
Got Array: { 1, 2, 3 }
i didnt understand your question to 100% but the implementation of what ever you gave will be like this
args.cpp:
#include<iostream>
using namespace std;
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; ++i)
{
std::cout << argv[i] << std::endl;
}
return 0;
}
compilation and output :
~/c++practise>g++ args.cpp
~/c++practise> ./a.out {33,44,77,88} {10,20,30}
./a.out
33
44
77
88
10
20
30

Split string into INT array in c [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I got string containing numbers separated by spaces. Numbers can be single-digit, two-digit, or perhaps more-digit. Check the example.
"* SEARCH 2 4 5 12 34 123 207"
I don't know how long the string is (how many numbers it contains), so I cant initiate the array properly. The result should look like this:
array = {2,4,5,12,34,123,207}
Do you have any ideas how to perform this?
like this:
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *input = "* SEARCH 2 4 5 12 34 123 207";
int len = 0;
sscanf(input, "%*[^0-9]%n", &len);//count not-digits(The Number isn't negative)
char *p = input + len;
char *start = p;
int v, n = 0;
while(1 == sscanf(p, "%d%n", &v, &len)){
++n;//count elements
p += len;
}
int array[n];//or allocate by malloc(and free)
char *endp = NULL;
int i;
for(i = 0; i < n; ++i){
array[i] = strtol(start, &endp, 10);
start = endp + 1;
}
//check print
for(i = 0; i < n; ++i)
printf("%d ", array[i]);
puts("");
return 0;
}
You can try this approach. It uses a temporary buffer to hold the current integer that is being processed. It also uses dynamic arrays, to deal with different lengths of the string you want to process, and expands them when necessary. Although using strtok Would be better in this situation.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int
main(int argc, char *argv[]) {
char message[] = "* SEARCH 2 4 5 12 34 123 207";
char *buffer = NULL;
int *integers = NULL;
int buff_size = 1, buff_len = 0;
int int_size = 1, int_len = 0;
int ch, messlen, i, first_int = 0;
/* creating space for dynamic arrays */
buffer = malloc((buff_size+1) * sizeof(*buffer));
integers = malloc(int_size * sizeof(*integers));
/* Checking if mallocs were successful */
if (buffer == NULL || integers == NULL) {
fprintf(stderr, "Malloc problem, please check\n");
exit(EXIT_FAILURE);
}
messlen = strlen(message);
/* going over each character in string */
for (ch = 0; ch < messlen; ch++) {
/* checking for first digit that is read */
if (isdigit(message[ch])) {
first_int = 1;
/* found, but is there space available? */
if (buff_size == buff_len) {
buff_size++;
buffer = realloc(buffer, (2*buff_size) * sizeof(*buffer));
}
buffer[buff_len++] = message[ch];
buffer[buff_len] = '\0';
}
/* checking for first space after first integer read */
if (isspace(message[ch]) && first_int == 1) {
if (int_size == int_len) {
int_size++;
integers = realloc(integers, (2*int_size) * sizeof(*integers));
}
integers[int_len] = atoi(buffer);
int_len++;
/* reset for next integer */
buff_size = 1;
buff_len = 0;
first_int = 0;
}
/* for last integer found */
if (isdigit(message[ch]) && ch == messlen-1) {
integers[int_len] = atoi(buffer);
int_len++;
}
}
printf("Your string: %s\n", message);
printf("\nYour integer array:\n");
for (i = 0; i < int_len; i++) {
printf("%d ", integers[i]);
}
/* Being careful and always free at the end */
/* Always a good idea */
free(integers);
free(buffer);
return 0;
}
You can read each character and verify if it is in range of >=48(Ascii of 0) and less than = 57(Ascii of 9). If so is the case read them into a array Otherwise you could copy them to a temporary string and convert to int using functions like atoi()
#include <stdio.h>
int main(int argc, char *argv[])
{
int j=0,k,res;
char buff[10];
while(str[j])
{
if((str[j]>='0')&&(str[j]<='9'))
{
k=0;
while((str[j]!=' ')&&(str[j]!='\0'))
{
buff[k]=str[j++];
k++;
}
buff[k]=0;
res=atoi(buff);
//Store this result to an array
}
j++;
}
return 0;
}

Read a txt file with gets in C

I want to know what is the best option to read a txt file that contain two line of numbers using gets function in c and save them in an array within 1 second.
Assume the following example as an txt file called ooo.txt and it has the number 2.000.000 in the first line (which will be the size of the array) and 2.000.000 number in the second line that will be stored in the array.
Eg
2000000
59 595 45 492 89289 5 8959 (+1.999.993 numbers)
code i try (only the fcanf function)
int t_size;
fscanf(fp, "%d",&t_size); //bypass the first character!
int* my_array = NULL;
my_array = malloc(t_size*sizeof(*my_array));
if (my_array==NULL) {
printf("Error allocating memory!\n"); //print an error message
return 1; //return with failure
getchar();
}
int i =0;
for ( i = 0; i < t_size; i++ )
{
fscanf(fp, "%d",&my_array[i]); /*p[i] is the content of element at index i and &p[i] is the address of element at index i */
}
best, so far, code to make the procedure in 1 second
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <time.h>
int is_end(char* input) {
return *input == 0;
}
int is_linebreak(char* input) {
return *input == '\r' || *input == '\n' || *input == ' ';
}
char* eat_linebreaks(char* input) {
while (is_linebreak(input))
++input;
return input;
}
size_t count_lines(char* input) {
char* p = input;
size_t rows = 1;
if (is_end(p))
return 0;
while (!is_end(p)) {
if (is_linebreak(p)) {
++rows;
p = eat_linebreaks(p);
}
else {
++p;
}
}
return rows;
}
/* split string by lines */
char** get_lines(char* input, size_t line_count) {
char* p = input;
char* from = input;
size_t length = 0;
size_t line = 0;
int i;
char** lines = (char**)malloc(line_count * sizeof(char*));
do {
if (is_end(p) || is_linebreak(p)) {
lines[line] = (char*)malloc(length + 1);
for (i = 0; i < length; ++i)
lines[line][i] = *(from + i);
lines[line][length] = 0;
length = 0;
++line;
p = eat_linebreaks(p);
from = p;
}
else {
++length;
++p;
}
} while (!is_end(p));
// Copy the last line as well in case the input doesn't end in line-break
lines[line] = (char*)malloc(length + 1);
for (i = 0; i < length; ++i)
lines[line][i] = *(from + i);
lines[line][length] = 0;
++line;
return lines;
}
int main(int argc, char* argv[]) {
clock_t start;
unsigned long microseconds;
float seconds;
char** lines;
size_t size;
size_t number_of_rows;
int count;
int* my_array;
start = clock();
FILE *stream;
char *contents;
int fileSize = 0;
int i;
// Open file, find the size of it
stream = fopen(argv[1], "rb");
fseek(stream, 0L, SEEK_END);
fileSize = ftell(stream);
fseek(stream, 0L, SEEK_SET);
// Allocate space for the entire file content
contents = (char*)malloc(fileSize + 1);
// Stream file into memory
size = fread(contents, 1, fileSize, stream);
contents[size] = 0;
fclose(stream);
// Count rows in content
number_of_rows = count_lines(contents);
// Get array of char*, one for each line
lines = get_lines(contents, number_of_rows);
// Get the numbers out of the lines
count = atoi(lines[0]); // First row has count
my_array = (int*)malloc(count * sizeof(int));
for (i = 0; i < count; ++i) {
my_array[i] = atoi(lines[i + 1]);
}
microseconds = clock() - start;
seconds = microseconds / 1000000.0f;
printf("Took %fs", seconds);
return 0;
}
First of all, you will want to use fgets instead to avoid dangerous buffer overflows. Second, you want to remove all punctuation from your numbers. Thus 2.000.000 becomes 2000000. Then you can use pointers and the strtol function to convert characters to integers; there are also other functions to convert to floats and other types.
Since code wants speed and IO is a typically bottle-neck, reading the entire file at once after using fstat() to find its length (#Charlon) makes some sense. Following is a quick parsing of that buffer.
// Stream file into memory
size = fread(contents, 1, fileSize, stream);
contents[size] = 0;
fclose(stream);
#if 1
// new code
size_t array_n;
int n;
if (sscanf(contents, "%zu%n", &array_n, &n) != 1) Handle_BadInput();
my_array = malloc(array_n * sizeof *my_array);
if (my_array == NULL) Handle_OOM();
char *p = &contents[n];
errno = 0;
char *endptr;
for (size_t count = 0; count < array_n; count++) {
my_array[count] = strtol(p, &endptr, 10);
if (p == endptr || errno)
Handle_BadInput();
p = endptr;
}
char ch;
if (sscanf(p, " %c", &ch) == 1) Handle_ExtraInput();
#else
//old code
// Count rows in content
number_of_rows = count_lines(contents);
// Get array of char*, one for each line
lines = get_lines(contents, number_of_rows);
// Get the numbers out of the lines
count = atoi(lines[0]); // First row has count
my_array = (int*)malloc(count * sizeof(int));
for (i = 0; i < count; ++i) {
my_array[i] = atoi(lines[i + 1]);
}
#endif
Still prefer the scale-able approach of reading one number at a time.
The fastest way needs a lot of RAM :
1) open the file (man open)
2) use the fstat function to get the size of you file (man fstat)
3) read the file with a buffer malloc-ed with the size you just get at 2) (man malloc)
4) close the file (man close)
5) parse your buffer and transform each block of digits (each time until ' ' or '\0') to int
EDIT : if your RAM is not enough large, you need to create a get_next_int function that only stores in your buffer the next number in the file
EDIT 2 : You can read until you know the number of int you will need to store and compares this number with a security coef to the size of your ram, and use the good way so that your program won't set errno to ENOMEM if you know what I'm talking about ;)

Resources