I'm trying to concatenate part of a struct with hex values. I run over every byte in the loop and convert to hex, then I want to concatenate all the hex into one long string.
However, I only end up with one value at the end of the loop. For some reason the string isnt concatenating properly. Any idea what Im doing wrong?
typedef struct OPTIONS_STR
{
int max;
int printName;
} OPTIONS;
void set_default_options(OPTIONS *options)
{
options->max = -1;
options->printName = 0;
}
void do_file(FILE *in, FILE *out, OPTIONS *options)
{
char ch;
int loop = 0;
char buf[81];
buf[0] = '\0';
int sz1;
int sz2;
int sz3;
int seeker = offsetof(struct myStruct, contents.datas);
//find total length of file
fseek(in, 0L, SEEK_END);
sz1 = ftell(in);
//find length from beggining to struct beginning and minus that from total length
fseek(in, seeker, SEEK_SET);
sz2 = sz1 - ftell(in);
//set seek location at beginning of struct offset
fseek(in, seeker, SEEK_SET);
sz3 = sz2 + 1;
char buffer[sz3];
char msg[sz3];
buffer[0] = '\0';
while (loop < sz2)
{
if (loop == sz2)
{
break;
}
fread(&ch, 1, 1, in);
sprintf(msg, "%02X", (ch & 0x00FF));
strcpy(buffer, msg);
++loop;
}
printf("%s\n", buffer);
}
int main(int argc, const char * argv[]) {
OPTIONS options;
set_default_options(&options);
const char *current = "/myfile.txt";
FILE *f = fopen(current, "rb");
do_file(f, stdout, &options);
fclose(f);
};
Use strcat instead of strcpy. That should fix your problem.
For efficiency look into using a write pointer like char *p = buffer and advance the write position with something like p += sprintf(p, "%02X", (ch & 0x00FF))
Also your if(loop == sz2) break check is a useless duplicate of the while(loop < sz2) check. The while loop won't execute if loop is equal or bigger than sz2.
Also wondering why you use fread when you only want one character. fgetc or getc seems to be a better choice.
Also, no matter if you use fread or getc you need to check for the end of file. What if the file does not have sz2 bytes in it? Because all modern systems are multiprocess and multiuser, so someone might cut the file short after the call to ftell. You should never assume things because even if you just checked it, it can change. Making that assumption is what causes TOCTTOU (Time of Check To Time Of Use) bugs.
In do_file(), you are copying the hex value for a single byte in a while loop. Thus, you should go to the next byte of character array buffer with each iteration of the while loop i.e. buffer++ or strcpy(buffer[loop], msg);
Related
I want to approach the string as an array, cut it to a specific length, and store it in a two-dimensional array. For example, I have 20 lines of text file. like this "input.txt"
www.google.com
www.naver.com
kbphonemall.com
kbplant.com
k-bplus.com
kbpointreestore.com
kbprint.com
kbprism.com
kbprivatebanking.com
kbpstore.com
kbr9rtudaf5ppy.com
kbrafting.com
kbraille.com
kbrainbank.com
kbrainbow.com
kbrainc.com
kbrainglocal.com
kbrandexpo.com
kbrandingschool.com
kbrandmall.com
and Then, I read this file and tried to crop it on each line using "\n as the key.
For example If you want to cut four lines at a time, you should cut it to "kbplant.com" first. And the truncated string looks like this.
www.google.com\nwww.naver.com\nkbphonemall.com\nkbplant.com\n
and It will then be stored in a pointer array. like this
char *cutting[n];
cutting[0] = "www.google.com\nwww.naver.com\nkbphonemall.com\nkbplant.com\n"
cutting[1] = "k-bplus.com\nkbpointreestore.com\nkbprint.com\nkbprism.com\n"
.... more
So far, that's the explanation of the functions I want to implement and I'll show you the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IPATH "input.txt"
int main(int argc, char *argv[]) {
char *ListBuffer;
int ListSize;
FILE *InputFile = fopen(IPATH, "r");
fseek(InputFile, 0, SEEK_END);
ListSize = ftell(InputFile);
ListBuffer = malloc(ListSize);
memset(ListBuffer, 0, ListSize);
fseek(InputFile, 0, SEEK_SET);
fread(ListBuffer, ListSize, 1, InputFile);
int count = 0;
ListBuffer[ListSize] = '\0'; //add NULL word
for (int i = 0; i <= ListSize; i++) {
if (ListBuffer[i] == '\n') {
count++;
if (count == 4) {
printf("c%d\n", i);
count = 0;
}
}
if (ListBuffer[i] == 0) {
printf("c%d\n", i);
count = 0;
}
}
fclose(InputFile);
free(ListBuffer);
ListBuffer = NULL;
}
this is my code I have used various functions such as strcpy function, strtok function, memcpy function, etc., but it was difficult to implement the desired function. Is there a better way or algorithm?
If you need more explanation, I'll answer it quickly.
I would appreciate it if you could reply. Have a good day.
It is unclear what you are trying to achieve in the main loop, but there are more problems:
you must allocate one extra byte to set the null terminator at ListSize:
ListBuffer = malloc(ListSize + 1);
it is useless to set the array to 0 with memset: allocating with calloc(1, ListSize + 1) would be more efficient for this purpose, but since you read the contents into the array, clearing it first is useless.
fread might return a short count, for example in text mode on legacy systems, converting CR/LR sequences to newline bytes \n reduces the number of bytes read:
ListSize = fread(ListBuffer, 1, ListSize, InputFile);
ListBuffer[ListSize] = '\0'; // set the null terminator
I'm supposed to copy fp to lines.
I first find the length of the texts in fp
then I dynamically allocate lines and retrieve the texts using fgets.
I keep getting a "Your return code was -11 but it was supposed to be 0" on my auto grader. This is only part of the code of course. I have a makefile and main.
Where is my seg fault??
void read_lines(FILE* fp, char*** lines, int* num_lines){
int num_chars=0;
int index=0;
int lengths[index];
int i=0;
//find the length of the rows n cols in fp
//while there is still character in the text
while(!feof(fp)){
//get that character
char current_char= fgetc(fp);
//implement the number character
num_chars++;
//enter at the end of the first then each line
if(current_char=='\n'){
//find the length of the next line of sentence/word.
// This array stores the length of characters of each line
lengths[index]= num_chars;
//update index
index++;
// Reset the number of characters for next iteration
num_chars = 0;
// Increment the number of lines read so far
(*num_lines)++;
}
}
//now we need to copy the characters in fp to lines
(*lines)=(char**) malloc((*num_lines)*sizeof(char*));
for(i=0;i<*num_lines;i++){
(*lines)[i]=(char*)malloc(lengths[i]*sizeof(char));
fgets(*lines[i],(lengths[i]+1),fp);
fseek(fp,0,SEEK_SET);
}
}
I'm seeing two problems, here.
First, lengths is statically allocated with zero bytes. That can and will never work. You will need to either create a lengths array with a maximum size (say, 256 line maximum) or make lengths a linked list so that it can grow with the index. Alternatively, you can make two passes through the file - once to get the number of lines (after which you allocate your lines array) and once to get the number of characters per line.
Second, although it is a nitpick, you can greatly simplify the code by removing num_lines from your while loop. After of the loop, just set
*num_lines = index;
The reason of segfault is your are passing lines pointer in wrong way
fgets(*lines[i],(lengths[i]+1),fp);
correct way is :-
fgets((*lines)[i],(lengths[i]+1),fp);
fix like this
void read_lines(FILE *fp, char ***lines, int *num_lines){
int num_chars=0;
/* int index=0; int lengths[index];//lengths[0] is bad. */
int ch, i = 0, max_length = 0;
while((ch=fgetc(fp))!=EOF){//while(!feof(fp)){ is bad. Because it loops once more.
num_chars++;
if(ch == '\n'){
++i;//count line
if(num_chars > max_length)
max_length = num_chars;
//reset
num_chars = 0;
}
}
if(num_chars != 0)//There is no newline in the last line
++i;
*num_lines = i;
rewind(fp);//need Need rewind
char *line = malloc(max_length + 1);
*lines = malloc(*num_lines * sizeof(char*));
for(i = 0; i < *num_lines; i++){
fgets(line, max_length+1, fp);
(*lines)[i] = malloc(strlen(line)+1);
strcpy((*lines)[i], line);
}
free(line);
}
For an assignment in class we were tasked with using the read() function to read a file containing numbers. While I was able to read the numbers into a buffer I have been unable to move them from the buffer into a char *array so that they can be easily accessed and sorted. Any advice is appreciated.
int readNumbers(int hexI, int MAX_FILENAME_LEN, int **array, char* fname) {
int numberRead = 0, cap = 2;
*array = (int *)malloc(cap*sizeof(int));
int n;
int filedesc = open(fname, O_RDONLY, 0);
if(filedesc < 0){
printf("%s: %s\n", "COULD NOT OPEN", fname);
return -1;
}
char * buff = malloc(512);
buff[511] = '\0';
while(n = read(filedesc, buff+totaln, 512 - totaln) > 0) //Appears to loop only once
totaln += n;
int len = strlen(buff);
for (int a = 0; a < len; a++) { //Dynamically allocates array according to input size
if ((&buff[a] != " ") && (&buff[a] != '\n'))
numberRead++;
if (numberRead >= cap){
cap = cap*2;
*array = (int*)realloc(*array, cap*sizeof(int));
}
}
int k = 0;
while((int *)&buff[k]){ //attempts to assign contents of buff to array
array[k] = (int *)&buff[k];
k++;
}
}
Your use of read() is wrong. There are at least two serious errors:
You ignore the return value, except to test for end-of-file.
You seem to assume that read() will append a nul byte after the data it reads. Perhaps even that it will pad out the buffer with nul bytes.
If you want to read more data into the same buffer after read() returns, without overwriting what you already read, then you must pass a pointer to the first available position in the buffer. If you want to know how many bytes were read in total, then you need to add the return values. The usual paradigm is something like this:
/*
* Read as many bytes as possible, up to buf_size bytes, from file descriptor fd
* into buffer buf. Return the number of bytes read, or an error code on
* failure.
*/
int read_full(int fd, char buf[], int buf_size) {
int total_read = 0;
int n_read;
while ((n_read = read(fd, buf + total_read, buf_size - total_read)) > 0) {
total_read += n_read;
}
return ((n_read < 0) ? n_read : total_read);
}
Having done something along those lines and not received an error, you can be assured that read() has not modified any element of the buffer beyond buf[total_read - 1]. It certainly has not filled the rest of the buffer with zeroes.
Note that it is not always necessary or desirable to read until the buffer is full; the example function does that for demonstration purposes, since it appears to be what you wanted.
Having done that, be aware that you are trying to extract numbers as if they were recorded in binary form in the file. That may indeed be the case, but if you're reading a text file containing formatted numbers then you need to extract the numbers differently. If that's what you're after then add a string terminator after the last byte read and use sscanf() to extract the numbers.
I'm very new to C and I'm still learning the basics. I'm creating an application that reads in a text file and breaks down the words individually. My intention will be to count the amount of times each word occurs.
Anyway, the last do-while loop in the code below executes fine, and then crashes. This loop prints memory address to this word (pointer) and then prints the word. It accomplishes this fine, and then crashes on the last iteration. My intention is to push this memory address into a singly linked list, albeit once it's stopped crashing.
Also, just a quick mention regarding the array sizes below; I yet figured out how to set the correct size needed to hold the word character array etc because you must define the size before the array is filled, and I don't know how to do this. Hence why I've set them to 1024.
#include<stdio.h>
#include<string.h>
int main (int argc, char **argv) {
FILE * pFile;
int c;
int n = 0;
char *wp;
char wordArray[1024];
char delims[] = " "; // delims spaces in the word array.
char *result = NULL;
result = strtok(wordArray, delims);
char holder[1024];
pFile=fopen (argv[1],"r");
if (pFile == NULL) perror ("Error opening file");
else {
do {
c = fgetc (pFile);
wordArray[n] = c;
n++;
} while (c != EOF);
n = 0;
fclose (pFile);
do {
result = strtok(NULL, delims);
holder[n] = *result; // holder stores the value of 'result', which should be a word.
wp = &holder[n]; // wp points to the address of 'holder' which holds the 'result'.
n++;
printf("Pointer value = %d\n", wp); // Prints the address of holder.
printf("Result is \"%s\"\n", result); // Prints the 'result' which is a word from the array.
//sl_push_front(&wp); // Push address onto stack.
} while (result != NULL);
}
return 0;
}
Please ignore the bad program structure, as I mentioned, I'm new to this!
Thanks
As others have pointed out, your second loop attempts to dereference result before you check for it being NULL. Restructure your code as follows:
result = strtok( wordArray, delims ); // do this *after* you have read data into
// wordArray
while( result != NULL )
{
holder[n] = *result;
...
result = strtok( NULL, delims );
}
Although...
You're attempting to read the entire contents of the file into memory before breaking it up into words; that's not going to work for files bigger than the size of your buffer (currently 1K). If I may make a suggestion, change your code such that you're reading individual words as you go. Here's an example that breaks the input stream up into words delimited by whitespace (blanks, newlines, tabs, etc.) and punctuation (period, comma, etc.):
#include <stdio.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char buffer[1024];
int c;
size_t n = 0;
FILE *input = stdin;
if( argc > 1 )
{
input = fopen( argv[1], "r");
if (!input)
input = stdin;
}
while(( c = fgetc(input)) != EOF )
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
fclose(input);
return 0;
}
No warranties express or implied (having pounded this out before 7:00 a.m.). But it should give you a flavor of how to parse a file as you go. If nothing else, it avoids using strtok, which is not the greatest of tools for parsing input. You should be able to adapt this general structure to your code. For best results, you should abstract that out into its own function:
int getNextWord(FILE *stream, char *buf, size_t bufsize)
{
int c;
size_t n = 0;
while(( c = fgetc(input)) != EOF && n < bufsize)
{
if (isspace(c) || ispunct(c))
{
if (n > 0)
{
buf[n] = 0;
n = 0;
}
}
else
{
buffer[n++] = c;
}
}
if (n > 0)
{
buffer[n] = 0;
printf("read word %s\n", buffer);
}
if (n == 0)
return 0;
else
return 1;
}
and you would call it like
void foo(void)
{
char word[SOME_SIZE];
...
while (getNextWord(inFile, word, sizeof word))
{
do_something_with(word);
}
...
}
If you expect in your do...while code, that result could be null (this is the condition for loop break), how do you think this code-line:
holder[n] = *result;
must work? It seems to me, that it is the reason for crashing in your program.
Change do while loop to while
use
while (condition)
{
}
instead of
do {
}while(condition)
It is crashing because you are trying to derefrance a NULL pointer result in do while loop.
I work mostly with Objective-C and was just looking at your question for fun, but I may have a solution.
Before setting n=0; after your first do-while loop, create another variable called totalWords and set it equal to n, totalWords can be declared anywhere within the file (except within one of the do-while loops), but can be defined at the top to the else block since its lifetime is short:
totalWords = n;
then you can set n back to zero:
n = 0;
Your conditional for the final do-while loop should then say:
...
} while (n <= ++totalWords);
The logic behind the application will thus say, count the words in the file (there are n words, which is the totalWords in the file). When program prints the results to the console, it will run the second do-while loop, which will run until n is one result past the value of totalWords (this ensures that you print the final word).
Alternately, it is better practice and clearer for other programmers to use a loop and a half:
do {
result = strtok(NULL, delims);
holder[n] = *result;
wp = &holder[n];
printf("Pointer value = %d\n", wp);
printf("Result is \"%s\"\n", result);
//sl_push_front(&wp); // Push address onto stack.
if (n == totalWords) break; // This forces the program to exit the do-while after we have printed the last word
n++; // We only need to increment if we have not reached the last word
// if our logic is bad, we will enter an infinite loop, which will tell us while testing that our logic is bad.
} while (true);
I'm trying to write a program that takes in a plaintext file as it's argument and parses through it, adding all the numbers together and then print out the sum. The following is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
static int sumNumbers(char filename[])
{
int sum = 0;
FILE *file = fopen(filename, "r");
char *str;
while (fgets(str, sizeof BUFSIZ, file))
{
while (*str != '\0')
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
str++;
}
}
fclose(file);
return sum;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "Please enter the filename as the argument.\n");
exit(EXIT_FAILURE);
}
else
{
printf("The sum of all the numbers in the file is : %d\n", sumNumbers(argv[1]));
exit(EXIT_SUCCESS);
}
return 0;
}
And the text file I'm using is:
This a rather boring text file with
some random numbers scattered
throughout it.
Here is one: 87 and here is another: 3
and finally two last numbers: 12
19381. Done. Phew.
When I compile and try to run it, I get a segmentation fault.
You've not allocated space for the buffer.The pointer str is just a dangling pointer. So your program effectively dumps the data read from the file into memory location which you don't own, leading to the segmentation fault.
You need:
char *str;
str = malloc(BUFSIZ); // this is missing..also free() the mem once done using it.
or just:
char str[BUFSIZ]; // but then you can't do str++, you'll have to use another
// pointer say char *ptr = str; and use it in place of str.
EDIT:
There is another bug in:
while (fgets(str, sizeof BUFSIZ, file))
The 2nd argument should be BUFSIZ not sizeof BUFSIZ.
Why?
Because the 2nd argument is the maximum number of characters to be read into the buffer including the null-character. Since sizeof BUFSIZ is 4 you can read max upto 3 char into the buffer. That is reason why 19381 was being read as 193 and then 81<space>.
You haven't allocated any memory to populate str. fgets takes as its first argument a buffer, not an unassigned pointer.
Instead of char *str; you need to define a reasonably sized buffer, say, char str[BUFSIZ];
Because you've not allocated space for your buffer.
A number of people have already addressed the problem you asked about, but I've got a question in return. What exactly do you think this accomplishes:
if (isdigit(*str))
{
if (isdigit(*str))
{
sum += atoi(str);
str++;
while (isdigit(*str))
str++;
continue;
}
}
What's supposed to be the point of two successive if statements with the exact same condition? (Note for the record: neither one has an else clause).
You have declared char* str, but you have not set aside memory for it just yet. You will need to malloc memory for it.
Many memory related errors such as this one can be easily found with valgrind. I'd highly recommend using it as a debugging tool.
char *str;
str has no memory allocated for it. Either use malloc() to allocate some memory for it, or declared it with a predefined size.
char str[MAX_SIZE];
Your program has several bugs:
It does not handle long lines correctly. When you read a buffer of some size it may happen that some number starts at the end of the buffer and continues at the beginning of the next buffer. For example, if you have a buffer of size 4, there might be the input The |numb|er 1|2345| is |larg|e., where the vertical lines indicate the buffer's contents. You would then count the 1 and the 2345 separately.
It calls isdigit with a char as argument. As soon as you read any "large" character (greater than SCHAR_MAX) the behavior is undefined. Your program might crash or produce incorrect results or do whatever it wants to do. To fix this, you must first cast the value to an unsigned char, for example isdigit((unsigned char) *str). Or, as in my code, you can feed it the value from the fgetc function, which is guaranteed to be a valid argument for isdigit.
You use a function that requires a buffer (fgets) but you fail to allocate the buffer. As others noted, the easiest way to get a buffer is to declare a local variable char buffer[BUFSIZ].
You use the str variable for two purposes: To hold the address of the buffer (which should remain constant over the whole execution time) and the pointer for analyzing the text (which changes during the execution). Make these two variables. I would call them buffer and p (short for pointer).
Here is my code:
#include <ctype.h>
#include <stdio.h>
static int sumNumbers(const char *filename)
{
int sum, num, c;
FILE *f;
if ((f = fopen(filename, "r")) == NULL) {
/* TODO: insert error handling here. */
}
sum = 0;
num = 0;
while ((c = fgetc(f)) != EOF) {
if (isdigit(c)) {
num = 10 * num + (c - '0');
} else if (num != 0) {
sum += num;
num = 0;
}
}
if (fclose(f) != 0) {
/* TODO: insert error handling here. */
}
return sum;
}
int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; i++)
printf("%d\t%s\n", sumNumbers(argv[i]), argv[i]);
return 0;
}
Here is a function, that does your job:
static int sumNumbers(char* filename) {
int sum = 0;
FILE *file = fopen(filename, "r");
char buf[BUFSIZ], *str;
while (fgets(buf, BUFSIZ, file))
{
str=buf;
while (*str)
{
if (isdigit(*str))
{
sum += strtol(str, &str, 10);
}
str++;
}
}
fclose(file);
return sum;
}
This doesn't includes error handling, but works quite well. For your file, output will be
The sum of all the numbers in the file is : 19483