C Console Input - c

I can't seem to google this because everything turns up as C++ or C# (Side note: any easy way to search for C specific?). All I'm trying to figure out is how to accept a console string input in such a way that I know it's length so I can return it in reverse order by indexing backwards through it with a for loop. I've had a little C++ experience in the past, but never really used console IO. Any help appreciated, thanks.

Read with fgets().
Cope with a possible trailing \n.
Find length
print in reverse.
char buf[100];
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EOF();
buf[strcspn(buf, "\n")] = '\0'; // lop off potential trailing \n
size_t len = strlen(buf);
while (len) {
putc(buf[--len], stdout);
}

You can use the fgets function to read from the standard input.
char buf[80];
if (fgets(buf, 80, stdin) != NULL)
/* buf now contains the first 80 chars of the input */
Note: Do NOT use gets because it is dangerous--it can overflow the input buffer.

You'll need to set aside some space to store the input; since you don't know ahead of time how big the input will be, you'll have to get a little creative with the storage.
A common strategy is to use a smallish, fixed-size buffer to read from the input stream, and a dynamic, resizable buffer to store the complete string if it winds up being longer than what the fixed-size buffer can handle. This way you can read an arbitrarily long input line in discrete chunks, and then paste the chunks together, resizing the target buffer as necessary.
You'll read the fixed-size chunks from the console in a loop and store it to the dynamic buffer until you see a newline, at which point you exit the input loop. Ideally, your fixed-size buffer should be large enough to handle most reasonable cases, such that you don't need to extend the dynamic buffer.
Excessively wordy (untested!) example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INPUT_BUF_SIZE 21 // handle strings up to 20 characters in length
int main( void )
{
/**
* Set aside a fixed-size buffer to store input from the console. This
* buffer cannot be resized after it has been allocated.
*/
char inputBuf[INPUT_BUF_SIZE];
/**
* Dynamically allocate a buffer to store the final string;
* its initial size is the same as the fixed buffer. If necessary,
* this buffer may be extended with the realloc function. We're using
* calloc instead of malloc to make sure the initial array contents
* are set to 0.
*/
char *finalBuf = calloc( INPUT_BUF_SIZE, sizeof *finalBuf );
/**
* finalBufSize tracks the total size of the dynamic buffer; finalBufLen
* tracks the length of the string currently stored in the buffer.
* These are not the same thing.
*/
size_t finalBufSize = INPUT_BUF_SIZE;
size_t finalBufLen = 0; // initially no string stored in the buffer
/**
* Read from standard input into the fixed-size buffer; loop until
* we see EOF or there's an error on input.
*/
while ( fgets( inputBuf, sizeof inputBuf, stdin ) )
{
/**
* If there isn't enough space left in finalBuf to store
* the latest chunk, double the size of finalBuf. This strategy
* minimizes the number of times you have to call realloc (which
* can be expensive).
*/
if ( strlen( inputBuf ) + finalBufLen > finalBufSize )
{
/**
* *Always* assign the result of realloc to a temp variable; if the
* call fails it will return NULL, and if you overwrite the value
* of finalBuf with NULL, you'll lose your only reference to any
* previously allocated memory.
*/
char *tmp = realloc( finalBuf, finalBufSize * 2 );
if ( tmp )
{
finalBuf = tmp;
finalBufSize *= 2;
}
else
{
/**
* We can't extend the buffer anymore, so we'll exit the
* loop and work with what we have.
*/
fprintf( stderr, "Could not extend storage buffer, exiting input loop\n" );
break;
}
}
/**
* Append the input string to the target buffer.
*/
strcat( finalBuf, inputBuf );
finalBufLen = strlen( finalBuf );
/**
* Did we see a newline in the last input chunk? If so,
* remove that newline from the final string (unless you
* want to include that in your reversal) and exit
* the loop.
*/
char *newline = strchr( finalString, '\n' );
if ( newline )
{
*newline = 0; // overwrite the newline character with the string terminator
break;
}
}
At this point, finalBuf contains the input from the console, and you can reverse this string for output. Once you're done with it, release the memory that's been allocated with the free function like so:
free( finalBuf );
Ideally you'd separate all that input handling into its own function, but this is a good enough illustration for now.

This is my solution but with recursion:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
void reverseW(char *, int);
int main()
{
char tmp[N], *string;
printf("Type a String:\n");
scanf("%s", tmp);
string=(char*)malloc((strlen(tmp)+1)*sizeof(char));
if (string==NULL)
{
printf("Error !\n");
exit(0);
}
strcpy(string, tmp);
reverseW(string, strlen(string));
printf("\nThe reverse of %s is %s !\n", tmp, string);
free(string);
return 0;
}
void reverseW(char *word, int size)
{
char tmp;
if (size>1)
{
tmp=word[0];
word[0]=word[size-1];
word[size-1]=tmp;
reverseW(word+1, size-2);
}
return;
}

I wrote this function to put input from stdin into a buffer, for a cli project in uni.
It reads stdin char by char, it has no buffer overflow.
/*max line lenght*/
#define CLI_MAX_CMD_LEN 1024
/*get_line copies characters from stdin to buffer pointed by buf, stopping when a
carriage return or newline is encountered. It returns -1 on errors, otherwise strlen count */
int get_line(char *buf) {
int i,c;
for (i=0;i<CLI_MAX_CMD_LEN;i++) {
c = getchar();
switch (c) {
/*if terminating char is found an error has occurred*/
case '\0':
printf("found '\\0' instead of '\\n'\n");
return -1;
case '\t':
/*show possible commands*/
autocomplete(buf);
break;
case EOF:
/* prints the warning to stdout */
printf("End of file reached\n");
/* continue to execute following cases code */
case '\n':
case '\r':
buf[i] = '\0';
return i;
default :
buf[i] = c;
}
}
/*if end of buffer is reached put terminating char on last element
means that an error has occurred*/
buf[CLI_MAX_CMD_LEN] = '\0';
return -1;
}

Related

Is there a way to 'dynamically size' a char variable?

I didn't exactly know how to phrase the question title. Is there way to make a char get larger with every char I type? It's kind of hard to understand. Take a look at the code:
char t[100];
scanf("%c", &t);
Is there a way to make the char bigger than 100 indexes if needed?
Yes, but...
You cannot resize a fixed-size array like t in your example. You'll have to use dynamic memory routines such as malloc, calloc, or realloc to allocate and resize the buffer. Here's a typical implementation that starts with a small buffer and doubles its size as necessary:
#include <stdlib.h>
#include <stdio.h>
/**
* getInput
*
* Reads input from the specified stream into a character buffer, extending
* the buffer as necessary.
*
* Inputs:
*
* stream - the input stream
*
* Outputs: none
*
* Returns: pointer to a character buffer containing the input string.
*/
char *getInput( FILE *stream )
{
/**
* Track the physical size of our buffer, which is at least 1 greater
* than the number of characters stored in it. Since we double the
* buffer size on each realloc, this has to start as a non-zero value.
*/
size_t buffer_size = 1;
/**
* Track the number of characters read from the input stream. Once this
* count equals the buffer size, we need to extend the buffer.
*/
size_t characters_read = 0;
/**
* Pointer to our dynamically-allocated buffer.
*/
char *buffer = NULL;
int c;
/**
* Read characters from the input stream until we hit a newline or EOF.
*/
while ( ( c = fgetc( stream ) ) != EOF && c != '\n' )
{
/**
* Update the number of characters read.
*
* If the number of characters read equals the buffer size,
* then we need to extend the buffer. Typically, we double
* the buffer size.
*/
if ( ++characters_read == buffer_size )
{
/**
* Double the size of the buffer (if the buffer pointer is NULL,
* this will allocate the buffer). ALWAYS assign the result of
* realloc to a temporary pointer - if it fails, it will return NULL
* and leave the buffer unchanged. If you assign that NULL to your
* pointer variable, you'll lose your reference to that memory.
*/
char *tmp = realloc( buffer, sizeof *buffer * (buffer_size * 2) );
/**
* If the allocation is unsuccessful, write an error message and
* return the buffer in its current state.
*/
if ( !tmp )
{
fprintf( stderr, "getInput - failed to extend input buffer, returning what we have so far...\n" );
return buffer;
}
/**
* Otherwise, update our buffer pointer (which may have changed
* as a result of the malloc operation) and buffer size:
*/
buffer = tmp;
buffer_size *= 2;
}
/**
* Write the character to the buffer. Remember that arrays are
* 0-indexed, so the first character goes to index 0, second
* character goes to index 1, etc.
*/
buffer[characters_read-1] = c;
}
/**
* Terminate the string. The logic above should make sure that
* characters_read is *always* less than buffer_size, so we shouldn't
* need to check for overflow here.
*/
buffer[characters_read] = 0;
/**
* Some debugging output
*/
fprintf( stderr, "buffer_size = %zu\n", buffer_size );
fprintf( stderr, "characters_read = %zu\n", characters_read );
return buffer;
}
/**
* Simple main program to exercise the code above.
*/
int main( void )
{
printf( "Gimme something: " );
char *input = getInput( stdin );
if ( input )
{
printf( "You typed: \"%s\"\n", input );
free( input );
}
else
{
printf( "error getting input\n" );
}
return 0;
}
Some example runs:
jbode:input john.bode$ ./input
Gimme something: a
buffer_size = 2
characters_read = 1
You typed: "a"
jbode:input john.bode$ ./input
Gimme something: ab
buffer_size = 4
characters_read = 2
You typed: "ab"
jbode:input john.bode$ ./input
Gimme something: abc
buffer_size = 4
characters_read = 3
You typed: "abc"
jbode:input john.bode$ ./input
Gimme something: abcd
buffer_size = 8
characters_read = 4
You typed: "abcd"
Note that the buffer size is always at least 1 larger than the number of characters in the string.
Doubling the size of the buffer each time winds up being a little more runtime efficient in the end than extending it by a fixed amount each time through, because on average you're making fewer realloc calls (which can be an expensive operation). The tradeoff is that you may wind up with a buffer twice as big as you really need. Extending by a fixed amount should result in less wasted space, but see above about runtime. In the end, you may need to do some analysis to determine which way is best for the problem at hand.

How to read a command output with pipe and scanf()?

I need to be able to send the output of the GET command and store it into a variable inside my program, currently I'm doing it like this:
GET google.com | ./myprogram
And receiving it in my program with the following code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]){
char *a = (char *) malloc (10000000);
scanf("%[^\n]", a);
printf("%s\n",a);
return 0;
}
The problem I have is that the scanf function stops at a new line, and I need to be able to store the whole paragraph output from GET.
Any help will be appreciated. Thanks.
One possibility: Does GET include the size information in the headers? Could you use that to determine how much space to allocate, and how much data to read? That's fiddly though, and requires reading the data in dribs and drabs.
More simply, consider using POSIX (and Linux) getdelim() (a close relative of getline()) and specify the delimiter as the null byte. That's unlikely to appear in the GET output, so the whole content will be a single 'line', and getdelim() will allocate an appropriate amount of space automatically. It also tells you how long the data was.
#include <stdio.h>
int main(void)
{
char *buffer = 0;
size_t buflen = 0;
int length = getdelim(&buffer, &buflen, '\0', stdin);
if (length > 0)
printf("%*.*s\n", length, length, buffer);
free(buffer);
return 0;
}
scanf documentation says
These functions return the number of input items successfully
matched and assigned, which can be fewer than provided for, or even
zero in the event of an early matching failure. The value EOF is
returned if the end of input is reached before either the first
successful conversion or a matching failure occurs. EOF is also
returned if a read error occurs, in which case the error indicator for
the stream (see ferror(3)) is set, and errno is set indicate the
error.
https://www.freebsd.org/cgi/man.cgi?query=scanf&sektion=3
Have you considered writing a loop that calls scanf, monitors its return value and breaks out if EOF
Consider the following readall() function implemented in standard C:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char *readall(FILE *source, size_t *length)
{
char *data = NULL;
size_t size = 0;
size_t used = 0;
size_t n;
/* If we have a place to store the length,
we initialize it to zero. */
if (length)
*length = 0;
/* Do not attempt to read the source, if it is
already in end-of-file or error state. */
if (feof(source) || ferror(source))
return NULL;
while (1) {
/* Ensure there is unused chars in data. */
if (used >= size) {
const size_t new_size = (used | 65535) + 65537 - 32;
char *new_data;
new_data = realloc(data, new_size);
if (!new_data) {
/* Although reallocation failed, data is still there. */
free(data);
/* We just fail. */
return NULL;
}
data = new_data;
size = new_size;
}
/* Read more of the source. */
n = fread(data + used, 1, size - used, source);
if (!n)
break;
used += n;
}
/* Read error or other wonkiness? */
if (!feof(source) || ferror(source)) {
free(data);
return NULL;
}
/* Optimize the allocation. For ease of use, we append
at least one nul byte ('\0') at end. */
{
const size_t new_size = (used | 7) + 9;
char *new_data;
new_data = realloc(data, new_size);
if (!new_data) {
if (used >= size) {
/* There is no room for the nul. We fail. */
free(data);
return NULL;
}
/* There is enough room for at least one nul,
so no reason to fail. */
} else {
data = new_data;
size = new_size;
}
}
/* Ensure the buffer is padded with nuls. */
memset(data + used, 0, size - used);
/* Save length, if requested. */
if (length)
*length = used;
return data;
}
It reads everything from the specified file handle (which can be a standard stream like stdin or a pipe opened via popen()) into a dynamically allocated buffer, appends a nul byte (\0), and returns a pointer to the buffer. If not NULL, the actual number of characters read (so, not including the appended nul byte), is stored in the size_t pointed to by the second parameter.
You can use it to read binary data output by programs, say dot -Tpng diagram.dot or image converters, or even wget -O - output (getting data from specific URLs, text or binary).
You can use this for example thus:
int main(void)
{
char *src;
size_t len;
src = readall(stdin, &len);
if (!src) {
fprintf(stderr, "Error reading standard input.\n");
return EXIT_FAILURE;
}
fprintf(stderr, "Read %zu chars.\n", len);
/* As an example, print it to standard output. */
if (len > 0)
fwrite(src, len, 1, stdout);
free(src);
return EXIT_SUCCESS;
}
The readall() function has two quirks: it allocates memory in roughly 131072-byte chunks (but could vary if fread() were to return short reads), and pads the buffer with 7 to 15 nul bytes. (There are reasons why I like doing it this way, but it is all speculative and specific to the C libraries I tend to use, so it is not important.)
Although the ones used above work fine, you can change the size_new calculations if you prefer otherwise. Just make sure that they both are at least used + 1.

Using fgets with realloc()

I'm trying to create a function to read a single line from a file of text using fgets() and store it in a dynamically allocating char* using malloc()but I am unsure as to how to use realloc() since I do not know the length of this single line of text and do not want to just guess a magic number for the maximum size that this line could possibly be.
#include "stdio.h"
#include "stdlib.h"
#define INIT_SIZE 50
void get_line (char* filename)
char* text;
FILE* file = fopen(filename,"r");
text = malloc(sizeof(char) * INIT_SIZE);
fgets(text, INIT_SIZE, file);
//How do I realloc memory here if the text array is full but fgets
//has not reach an EOF or \n yet.
printf(The text was %s\n", text);
free(text);
int main(int argc, char *argv[]) {
get_line(argv[1]);
}
I am planning on doing other things with the line of text but for sake of keeping this simple, I have just printed it and then freed the memory.
Also: The main function is initiated by using the filename as the first command line argument.
The getline function is what you looking for.
Use it like this:
char *line = NULL;
size_t n;
getline(&line, &n, stdin);
If you really want to implement this function yourself, you can write something like this:
#include <stdlib.h>
#include <stdio.h>
char *get_line()
{
int c;
/* what is the buffer current size? */
size_t size = 5;
/* How much is the buffer filled? */
size_t read_size = 0;
/* firs allocation, its result should be tested... */
char *line = malloc(size);
if (!line)
{
perror("malloc");
return line;
}
line[0] = '\0';
c = fgetc(stdin);
while (c != EOF && c!= '\n')
{
line[read_size] = c;
++read_size;
if (read_size == size)
{
size += 5;
char *test = realloc(line, size);
if (!test)
{
perror("realloc");
return line;
}
line = test;
}
c = fgetc(stdin);
}
line[read_size] = '\0';
return line;
}
One possible solution is to use two buffers: One temporary that you use when calling fgets; And one that you reallocate, and append the temporary buffer to.
Perhaps something like this:
char temp[INIT_SIZE]; // Temporary string for fgets call
char *text = NULL; // The actual and full string
size_t length = 0; // Current length of the full string, needed for reallocation
while (fgets(temp, sizeof temp, file) != NULL)
{
// Reallocate
char *t = realloc(text, length + strlen(temp) + 1); // +1 for terminator
if (t == NULL)
{
// TODO: Handle error
break;
}
if (text == NULL)
{
// First allocation, make sure string is properly terminated for concatenation
t[0] = '\0';
}
text = t;
// Append the newly read string
strcat(text, temp);
// Get current length of the string
length = strlen(text);
// If the last character just read is a newline, we have the whole line
if (length > 0 && text[length - 1] == '\n')
{
break;
}
}
[Discalimer: The code above is untested and may contain bugs]
With the declaration of void get_line (char* filename), you can never make use of the line you read and store outside of the get_line function because you do not return a pointer to line and do not pass the address of any pointer than could serve to make any allocation and read visible back in the calling function.
A good model (showing return type and useful parameters) for any function to read an unknown number of characters into a single buffer is always POSIX getline. You can implement your own using either fgetc of fgets and a fixed buffer. Efficiency favors the use of fgets only to the extent it would minimize the number of realloc calls needed. (both functions will share the same low-level input buffer size, e.g. see gcc source IO_BUFSIZ constant -- which if I recall is now LIO_BUFSIZE after a recent name change, but basically boils down to an 8192 byte IO buffer on Linux and 512 bytes on windows)
So long as you dynamically allocate the original buffer (either using malloc, calloc or realloc), you can read continually with a fixed buffer using fgets adding the characters read into the fixed buffer to your allocated line and checking whether the final character is '\n' or EOF to determine when you are done. Simply read a fixed buffer worth of chars with fgets each iteration and realloc your line as you go, appending the new characters to the end.
When reallocating, always realloc using a temporary pointer. That way, if you run out of memory and realloc returns NULL (or fails for any other reason), you won't overwrite the pointer to your currently allocated block with NULL creating a memory leak.
A flexible implementation that sizes the fixed buffer as a VLA using either the defined SZINIT for the buffer size (if the user passes 0) or the size provided by the user to allocate initial storage for line (passed as a pointer to pointer to char) and then reallocating as required, returning the number of characters read on success or -1 on failure (the same as POSIX getline does) could be done like:
/** fgetline, a getline replacement with fgets, using fixed buffer.
* fgetline reads from 'fp' up to including a newline (or EOF)
* allocating for 'line' as required, initially allocating 'n' bytes.
* on success, the number of characters in 'line' is returned, -1
* otherwise
*/
ssize_t fgetline (char **line, size_t *n, FILE *fp)
{
if (!line || !n || !fp) return -1;
#ifdef SZINIT
size_t szinit = SZINIT > 0 ? SZINIT : 120;
#else
size_t szinit = 120;
#endif
size_t idx = 0, /* index for *line */
maxc = *n ? *n : szinit, /* fixed buffer size */
eol = 0, /* end-of-line flag */
nc = 0; /* number of characers read */
char buf[maxc]; /* VLA to use a fixed buffer (or allocate ) */
clearerr (fp); /* prepare fp for reading */
while (fgets (buf, maxc, fp)) { /* continuall read maxc chunks */
nc = strlen (buf); /* number of characters read */
if (idx && *buf == '\n') /* if index & '\n' 1st char */
break;
if (nc && (buf[nc - 1] == '\n')) { /* test '\n' in buf */
buf[--nc] = 0; /* trim and set eol flag */
eol = 1;
}
/* always realloc with a temporary pointer */
void *tmp = realloc (*line, idx + nc + 1);
if (!tmp) /* on failure previous data remains in *line */
return idx ? (ssize_t)idx : -1;
*line = tmp; /* assign realloced block to *line */
memcpy (*line + idx, buf, nc + 1); /* append buf to line */
idx += nc; /* update index */
if (eol) /* if '\n' (eol flag set) done */
break;
}
/* if eol alone, or stream error, return -1, else length of buf */
return (feof (fp) && !nc) || ferror (fp) ? -1 : (ssize_t)idx;
}
(note: since nc already holds the current number of characters in buf, memcpy can be used to append the contents of buf to *line without scanning for the terminating nul-character again) Look it over and let me know if you have further questions.
Essentially you can use it as a drop-in replacement for POSIX getline (though it will not be quite as efficient -- but isn't not bad either)

How to make string function with user input in C?

I know how to make function with int, double, float with user input inside(im currently using scanf).
int getData(){
int a;
scanf("%i",&a);
return a;
}
but how to make function with string type and user input inside, then we return that value with type string?
A C string is an array of char terminated by a NUL (zero) byte. Arrays are normally passed around as pointers to the first element. The problem with returning that from the function is that the address pointed to must remain valid beyond the lifetime of the function, which means it needs to be either a static buffer (which is then overwritten by any subsequent calls to the same function, breaking earlier returned values) or allocated by the function, in which case the caller is responsible for freeing it.
The scanf you mention is also problematic for reading interactive user input, e.g., it may leave the input in an unexpected state such as when you don't consume the newline at the end of a line the next call to scanf (maybe in an unrelated function) may surprisingly fail to give the expected result when it encounters the newline.
It is often simpler to read input into a buffer line-by-line, e.g., with fgets, and then parse the line from there. (Some inputs you may be able to parse without a buffer simply by reading character by character, but such code often gets long and hard to follow quickly.)
An example of reading any string, which may contain whitespace other than the newline, would be something like:
/// Read a line from stdin and return a `malloc`ed copy of it without
/// the trailing newline. The caller is responsible for `free`ing it.
char *readNewString(void) {
char buffer[1024];
if (!fgets(buffer, sizeof buffer, stdin)) {
return NULL; // read failed, e.g., EOF
}
int len = strlen(buffer);
if (len > 0 && buffer[len - 1] == '\n') {
buffer[--len] = '\0'; // remove the newline
// You may also wish to remove trailing and/or leading whitespace
} else {
// Invalid input
//
// Depending on the context you may wish to e.g.,
// consume input until newline/EOF or abort.
}
char *str = malloc(len + 1);
if (!str) {
return NULL; // out of memory (unlikely)
}
return strcpy(str, buffer); // or use `memcpy` but then be careful with length
}
Another option is to have the caller supply the buffer and its size, then just return the same buffer on success and NULL on failure. This approach has the
advantage that the caller may decide when a buffer is reused and whether the string needs to be copied or simply read once and forgotten.
Extending Arkku's approach to an unlimited size (in fact it is limited to SIZE_MAX - 1 characters) as input:
#include <stdlib.h>
#include <string.h>
#define BUFFER_MAX (256)
int read_string(FILE * pf, char ** ps)
{
int result = 0;
if (!ps)
{
result = -1;
errno = EINVAL;
}
else
{
char buffer[BUFFER_MAX];
size_t len = 0;
*ps = NULL;
while (NULL != fgets(buffer, sizeof buffer, pf))
{
len += strlen(buffer);
{
void * p = realloc(*ps, len + 1);
if (!p)
{
int es = errno;
result = -1;
free(*ps);
errno = es;
break;
}
*ps = p;
}
strcpy(&(*ps)[len], buffer);
}
if (ferror(pf))
{
result = -1;
}
}
return result;
}
Call it like this:
#include <stdlib.h>
#include <stdlio.h>
int read_string(FILE * pf, char ** ps);
int main(void);
{
char * p;
if (-1 == read_string(stdin, &p)) /* This read from standard input,
still any FILE* would do here. */
{
perror("read_string() failed");
exit(EXIT_FAILURE);
}
printf("Read: '%s'\n", p);
free(p); /* Clean up. */
}

C - cannot read and process a list of strings from a text file into an array

This code reads a text file line by line. But I need to put those lines in an array but I wasn't able to do it. Now I am getting a array of numbers somehow. So how to read the file into a list. I tried using 2 dimensional list but this doesn't work as well.
I am new to C. I am mostly using Python but now I want to check if C is faster or not for a task.
#include <stdio.h>
#include <time.h>
#include <string.h>
void loadlist(char *ptext) {
char filename[] = "Z://list.txt";
char myline[200];
FILE * pfile;
pfile = fopen (filename, "r" );
char larray[100000];
int i = 0;
while (!feof(pfile)) {
fgets(myline,200,pfile);
larray[i]= myline;
//strcpy(larray[i],myline);
i++;
//printf(myline);
}
fclose(pfile);
printf("%s \n %d \n %d \n ","while doneqa",i,strlen(larray));
printf("First larray element is: %d \n",larray[0]);
/* for loop execution */
//for( i = 10; i < 20; i = i + 1 ){
// printf(larray[i]);
//}
}
int main ()
{
time_t stime, etime;
printf("Starting of the program...\n");
time(&stime);
char *ptext = "String";
loadlist(ptext);
time(&etime);
printf("time to load: %f \n", difftime(etime, stime));
return(0);
}
This code reads a text file line by line. But I need to put those lines in an array but I wasn't able to do it. Now I am getting an array of numbers somehow.
There are many ways to do this correctly. To begin with, first sort out what it is you actually need/want to store, then figure out where that information will come from and finally decide how you will provide storage for the information. In your case loadlist is apparently intended load a list of lines (up to 10000) so that they are accessible through your statically declared array of pointers. (you can also allocate the pointers dynamically, but if you know you won't need more than X of them, statically declaring them is fine (up to the point you cause StackOverflow...)
Once you read the line in loadlist, then you need to provide adequate storage to hold the line (plus the nul-terminating character). Otherwise, you are just counting the number of lines. In your case, since you declare an array of pointers, you cannot simply copy the line you read because each of the pointers in your array does not yet point to any allocated block of memory. (you can't assign the address of the buffer you read the line into with fgets (buffer, size, FILE*) because (1) it is local to your loadlist function and it will go away when the function stack frame is destroyed on function return; and (2) obviously it gets overwritten with each call to fgets anyway.
So what to do? That's pretty simple too, just allocate storage for each line as it is read using the strlen of each line as #iharob says (+1 for the nul-byte) and then malloc to allocate a block of memory that size. You can then simply copy the read buffer to the block of memory created and assign the pointer to your list (e.g. larray[x] in your code). Now the gnu extensions provide a strdup function that both allocates and copies, but understand that is not part of the C99 standard so you can run into portability issues. (also note you can use memcpy if overlapping regions of memory are a concern, but we will ignore that for now since you are reading lines from a file)
What are the rules for allocating memory? Well, you allocate with malloc, calloc or realloc and then you VALIDATE that your call to those functions succeeded before proceeding or you have just entered the realm of undefined behavior by writing to areas of memory that are NOT in fact allocated for your use. What does that look like? If you have your array of pointers p and you want to store a string from your read buffer buf of length len at index idx, you could simply do:
if ((p[idx] = malloc (len + 1))) /* allocate storage */
strcpy (p[idx], buf); /* copy buf to storage */
else
return NULL; /* handle error condition */
Now you are free to allocate before you test as follows, but it is convenient to make the assignment as part of the test. The long form would be:
p[idx] = malloc (len + 1); /* allocate storage */
if (p[idx] == NULL) /* validate/handle error condition */
return NULL;
strcpy (p[idx], buf); /* copy buf to storage */
How you want to do it is up to you.
Now you also need to protect against reading beyond the end of your pointer array. (you only have a fixed number since you declared the array statically). You can make that check part of your read loop very easily. If you have declared a constant for the number of pointers you have (e.g. PTRMAX), you can do:
int idx = 0; /* index */
while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {
...
idx++;
}
By checking the index against the number of pointers available, you insure you cannot attempt to assign address to more pointers than you have.
There is also the unaddressed issue of handling the '\n' that will be contained at the end of your read buffer. Recall, fgets read up to and including the '\n'. You do not want newline characters dangling off the ends of the strings you store, so you simply overwrite the '\n' with a nul-terminating character (e.g. simply decimal 0 or the equivalent nul-character '\0' -- your choice). You can make that a simple test after your strlen call, e.g.
while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {
size_t len = strlen (buf); /* get length */
if (buf[len-1] == '\n') /* check for trailing '\n' */
buf[--len] = 0; /* overwrite '\n' with nul-byte */
/* else { handle read of line longer than 200 chars }
*/
...
(note: that also brings up the issue of reading a line longer than the 200 characters you allocate for your read buffer. You check for whether a complete line has been read by checking whether fgets included the '\n' at the end, if it didn't, you know your next call to fgets will be reading again from the same line, unless EOF is encountered. In that case you would simply need to realloc your storage and append any additional characters to that same line -- that is left for future discussion)
If you put all the pieces together and choose a return type for loadlist that can indicate success/failure, you could do something similar to the following:
/** read up to PTRMAX lines from 'fp', allocate/save in 'p'.
* storage is allocated for each line read and pointer
* to allocated block is stored at 'p[x]'. (you should
* add handling of lines greater than LNMAX chars)
*/
char **loadlist (char **p, FILE *fp)
{
int idx = 0; /* index */
char buf[LNMAX] = ""; /* read buf */
while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {
size_t len = strlen (buf); /* get length */
if (buf[len-1] == '\n') /* check for trailing '\n' */
buf[--len] = 0; /* overwrite '\n' with nul-byte */
/* else { handle read of line longer than 200 chars }
*/
if ((p[idx] = malloc (len + 1))) /* allocate storage */
strcpy (p[idx], buf); /* copy buf to storage */
else
return NULL; /* indicate error condition in return */
idx++;
}
return p; /* return pointer to list */
}
note: you could just as easily change the return type to int and return the number of lines read, or pass a pointer to int (or better yet size_t) as a parameter to make the number of lines stored available back in the calling function.
However, in this case, we have used the initialization of all pointers in your array of pointers to NULL, so back in the calling function we need only iterate over the pointer array until the first NULL is encountered in order to traverse our list of lines. Putting together a short example program that read/stores all lines (up to PTRMAX lines) from the filename given as the first argument to the program (or from stdin if no filename is given), you could do something similar to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
enum { LNMAX = 200, PTRMAX = 10000 };
char **loadlist (char **p, FILE *fp);
int main (int argc, char **argv) {
time_t stime, etime;
char *list[PTRMAX] = { NULL }; /* array of ptrs initialized NULL */
size_t n = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
printf ("Starting of the program...\n");
time (&stime);
if (loadlist (list, fp)) { /* read lines from fp into list */
time (&etime);
printf("time to load: %f\n\n", difftime (etime, stime));
}
else {
fprintf (stderr, "error: loadlist failed.\n");
return 1;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
while (list[n]) { /* output stored lines and free allocated mem */
printf ("line[%5zu]: %s\n", n, list[n]);
free (list[n++]);
}
return(0);
}
/** read up to PTRMAX lines from 'fp', allocate/save in 'p'.
* storage is allocated for each line read and pointer
* to allocated block is stored at 'p[x]'. (you should
* add handling of lines greater than LNMAX chars)
*/
char **loadlist (char **p, FILE *fp)
{
int idx = 0; /* index */
char buf[LNMAX] = ""; /* read buf */
while (fgets (buf, LNMAX, fp) && idx < PTRMAX) {
size_t len = strlen (buf); /* get length */
if (buf[len-1] == '\n') /* check for trailing '\n' */
buf[--len] = 0; /* overwrite '\n' with nul-byte */
/* else { handle read of line longer than 200 chars }
*/
if ((p[idx] = malloc (len + 1))) /* allocate storage */
strcpy (p[idx], buf); /* copy buf to storage */
else
return NULL; /* indicate error condition in return */
idx++;
}
return p; /* return pointer to list */
}
Finally, in any code your write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
Use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory, attempted to read or base a jump on an uninitialized value and finally to confirm that you have freed all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
Look things over, let me know if you have any further questions.
It's natural that you see numbers because you are printing a single character using the "%d" specifier. In fact, strings in c are pretty much that, arrays of numbers, those numbers are the ascii values of the corresponding characters. If you instead use "%c" you will see the character that represents each of those numbers.
Your code also, calls strlen() on something that is intended as a array of strings, strlen() is used to compute the length of a single string, a string being an array of char items with a non-zero value, ended with a 0. Thus, strlen() is surely causing undefined behavior.
Also, if you want to store each string, you need to copy the data like you tried in the commented line with strcpy() because the array you are using for reading lines is overwritten over and over in each iteration.
Your compiler must be throwing all kinds of warnings, if it's not then it's your fault, you should let the compiler know that you want it to do some diagnostics to help you find common problems like assigning a pointer to a char.
You should fix multiple problems in your code, here is a code that fixes most of them
void
loadlist(const char *const filename) {
char line[100];
FILE *file;
// We can only read 100 lines, of
// max 99 characters each
char array[100][100];
int size;
size = 0;
file = fopen (filename, "r" );
if (file == NULL)
return;
while ((fgets(line, sizeof(line), file) != NULL) && (size < 100)) {
strcpy(array[size++], line);
}
fclose(file);
for (int i = 0 ; i < size ; ++i) {
printf("array[%d] = %s", i + 1, array[i]);
}
}
int
main(void)
{
time_t stime, etime;
printf("Starting of the program...\n");
time(&stime);
loadlist("Z:\\list.txt");
time(&etime);
printf("Time to load: %f\n", difftime(etime, stime));
return 0;
}
Just to prove how complicated it can be in c, check this out
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
struct string_list {
char **items;
size_t size;
size_t count;
};
void
string_list_print(struct string_list *list)
{
// Simply iterate through the list and
// print every item
for (size_t i = 0 ; i < list->count ; ++i) {
fprintf(stdout, "item[%zu] = %s\n", i + 1, list->items[i]);
}
}
struct string_list *
string_list_create(size_t size)
{
struct string_list *list;
// Allocate space for the list object
list = malloc(sizeof *list);
if (list == NULL) // ALWAYS check this
return NULL;
// Allocate space for the items
// (starting with `size' items)
list->items = malloc(size * sizeof *list->items);
if (list->items != NULL) {
// Update the list size because the allocation
// succeeded
list->size = size;
} else {
// Be optimistic, maybe realloc will work next time
list->size = 0;
}
// Initialize the count to 0, because
// the list is initially empty
list->count = 0;
return list;
}
int
string_list_append(struct string_list *list, const char *const string)
{
// Check if there is room for the new item
if (list->count + 1 >= list->size) {
char **items;
// Resize the array, there is no more room
items = realloc(list->items, 2 * list->size * sizeof *list->items);
if (items == NULL)
return -1;
// Now update the list
list->items = items;
list->size += list->size;
}
// Copy the string into the array we simultaneously
// increase the `count' and copy the string
list->items[list->count++] = strdup(string);
return 0;
}
void
string_list_destroy(struct string_list *const list)
{
// `free()' does work with a `NULL' argument
// so perhaps as a principle we should too
if (list == NULL)
return;
// If the `list->items' was initialized, attempt
// to free every `strdup()'ed string
if (list->items != NULL) {
for (size_t i = 0 ; i < list->count ; ++i) {
free(list->items[i]);
}
free(list->items);
}
free(list);
}
struct string_list *
loadlist(const char *const filename) {
char line[100]; // A buffer for reading lines from the file
FILE *file;
struct string_list *list;
// Create a new list, initially it has
// room for 100 strings, but it grows
// automatically if needed
list = string_list_create(100);
if (list == NULL)
return NULL;
// Attempt to open the file
file = fopen (filename, "r");
// On failure, we now have the responsibility
// to cleanup the allocated space for the string
// list
if (file == NULL) {
string_list_destroy(list);
return NULL;
}
// Read lines from the file until there are no more
while (fgets(line, sizeof(line), file) != NULL) {
char *newline;
// Remove the trainling '\n'
newline = strchr(line, '\n');
if (newline != NULL)
*newline = '\0';
// Append the string to the list
string_list_append(list, line);
}
fclose(file);
return list;
}
int
main(void)
{
time_t stime, etime;
struct string_list *list;
printf("Starting of the program...\n");
time(&stime);
list = loadlist("Z:\\list.txt");
if (list != NULL) {
string_list_print(list);
string_list_destroy(list);
}
time(&etime);
printf("Time to load: %f\n", difftime(etime, stime));
return 0;
}
Now, this will work almost as the python code you say you wrote but it will certainly be faster, there is absolutely no doubt.
It is possible that an experimented python programmer can write a python program that runs faster than that of a non-experimented c programmer, learning c however is really good because you then understand how things work really, and you can then infer how a python feature is probably implemented, so understanding this can be very useful actually.
Although it's certainly way more complicated than doing the same in python, note that I wrote this in nearly 10min. So if you really know what you're doing and you really need it to be fast c is certainly an option, but you need to learn many concepts that are not clear to higher level languages programmers.

Resources