I am tring to print compose a function can get the specific line from a file, like string=extract_line(2), then the string will be the content of the 2nd line of a file.
but when I tried to put the function in a head file, I got Segmentation fault.
Here is my code:
test.c:
#include "extract_line.h"
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[])
{
extract_line(2);
extract_line(3);
printf("%s\n", str);
return 0;
}
extract_line.h
#include <stdio.h>
#include <stdlib.h>
#define TEMP_PATH "/home/pi/project/PCD_8544_screen/show_on_LCD/network_speed.txt"
static char str[256];
void extract_line( int Tgt_Line )
{
FILE *fp;
fp=fopen(TEMP_PATH, "r");
// char str[256];
char holder;
int line=0;
while((holder=fgetc(fp)) != EOF) {
if(holder == '\n') line++;
if(line == Tgt_Line) break; /* 1 because count start from 0,you know */
}
if(holder == EOF) {
printf("%s doesn't have the 2nd line\n", fp);
//error:there's no a 2nd
}
int i=0;
while((holder=fgetc(fp)) != EOF && (holder != '\n' )) {
// putchar(holder);
str[i] = holder;
i++;
}
// printf("%s\n",str);
fclose(fp);
// return str;
}
In the following line of code:
printf("%s doesn't have the 2nd line\n", fp);
You're printing a FILE * as though it's expected to point at a string (filename?). As printf expects a char *, this is likely to cause irrational behaviour. Note that your compiler is probably SCREAMING at you about this! Perhaps you meant:
printf("%s doesn't have the 2nd line\n", TEMP_PATH);
Additionally, there's a possibility for a null pointer dereference which would also cause irrational behaviour between the following two lines:
fp=fopen(TEMP_PATH, "r");
// snip! you need to check fp here!
while((holder=fgetc(fp)) != EOF) {
On that note, your loop is infinite on systems where char is an unsigned type, as EOF is negative which can't possibly compare equal to any unsigned values. As fgetc returns an int with an unsigned char within it and holder is a char, the downward conversion discards the information required for your loop to terminate. holder should be defined as an int, instead.
As there's no upper bound on how many characters are read set by your loop, it's possible that str may be accessed (and assigned) out of bounds in str[i] = holder;. This could cause irrational behaviour.
Additionally, it appears there's no explicit assignment of a '\0' string terminator. As str is defined with static storage duration (not to be confused with your static keyword, which provides internal linkage), that won't really cause irrational behaviour, in fact it's quite predictable, but your output might not be as you expect if the first call reads a line longer than the second call.
Finally, just a few nitpick notes:
I suggest using size_t rather than int for variables which are expected to count or refer to array elements (e.g. int i=0; should be size_t i=0;). This is to make it explicit that negative numbers aren't acceptable, which might also speed your code up a little.
It's a little bit strange to put code in header files. Usually definitions only go into header files, which we #include, and code goes into code files, which we link to (e.g. gcc -o x.c compiles x.c, then gcc main.c x.o compiles main.c and links it with x.o).
You need to have a main() function or you need to run the script from within any other function..
#include "extract_line.h"
#include <stdio.h>
#include <stdlib.h>
void main() {
extract_line(2);
extract_line(3);
printf("%s\n", str);
}
Related
I am trying to read a file line by line, and get each line as a charĀ * to a dynamic string, the code I am using used to work and without changing it (or noticing it), it has ceased to work, accsesing the reed information results in an error. Here is a MRE of my code for getting one line:
#include <stdio.h>
#include <string.h>
#define MAX_STR_SIZE 10000
int main(void)
{
char* filePath; // is set by other working part of program to a real readable file address.
while (fgetc(filePath) != EOF) // an extra chracter is in the data files to account for this cheack.
{
char tempStr[MAX_STR_SIZE] = { 0 };
char* str = NULL;
fgets(tempStr, MAX_STR_SIZE, filePath);
tempStr[strcspn(tempStr, "\n")] = 0;
str = malloc(sizeof(char) * (strlen(tempStr) + 1)); // does not work
strcpy(str, tempStr);
}
}
The error:
Exception thrown at 0x00007ff95448d215 in GifProject.exe: Access violation writing location 0xFFFFFFFFEA1854F0.
It is difficult to diagnose your problem without a complete compilable program that exhibits the problem, but from the code fragment and the debugging information in the image, it seems you do not include <stdlib.h> and the prototype inferred by the compiler for malloc() from the actual argument is int malloc(size_t), leading to undefined behavior when you store the return value into the pointer str: because of the missing prototype, the compiler generates code that converts the return value from int to char *, sign extending from 32-bit to 64-bits, producing a meaningless pointer.
Note that you should also test the return value of fgets to properly handle end of file, and you should test for potential malloc failure before calling strcpy or better: use strdup that allocates and copies a string in a single call.
Here is a modified version:
#include <stdlib.h>
#include <string.h>
#define MAX_STR_SIZE 4096
char *readline(FILE *file) {
char tempStr[MAX_STR_SIZE];
if (!fgets(tempStr, sizeof tempStr, file)) {
/* end of file: return a null pointer */
return NULL;
}
/* strip the trailing newline if any */
tempStr[strcspn(tempStr, "\n")] = '\0';
/* allocate a copy of the string and return it */
return strdup(tempStr);
}
So I suck with functions and need to debug this. Im pretty sure the function ToPigLating does its job well at converting. However I just need help calling the function ToPigLatin inside of my main function. But when I try doing that I just get a bunch of error codes.
#include <stdlib.h>
#include <string.h>
#define LEN 32
char* ToPigLatin(char* word[LEN]){
char word[LEN];
char translation [LEN];
char temp [LEN];
int i, j;
while ((scanf ("%s", word)) != '\0') {
strcpy (translation, word);
//just pretend I have all the work to convert it in here.
} // while
}
int main(){
printf("Enter 5 words: ");
scanf("%s", word);
ToPigLatin();
}```
Roughly, variables only exist within the function they're declared in. The word in ToPigLatin exists only within ToPigLatin. It is not available in main. This lets us write functions without worrying about all the rest of the code.
You need to declare a different variable in main, it can also be called word, to store the input and then pass that into ToPigLatin.
Let's illustrate with something simpler, a function which doubles its input.
int times_two(int number) {
return number * 2;
}
We need to give times_two a number.
int main() {
// This is different from "number" in times_two.
int number = 42;
// We have to pass its value into time_two.
int doubled = times_two(number);
printf("%d doubled is %d\n", number, doubled);
}
Your case is a bit more complicated because you're working with input and memory allocation and arrays. I'd suggest just focusing on arrays and function calls for now. No scanf. No strcpy.
For example, here's a function to print an array of words.
#include <stdio.h>
// Arrays in C don't store their size, the size must be given.
void printWords(const char *words[], size_t num_words) {
for( int i = 0; i < num_words; i++ ) {
printf("word[%d] is %s.\n", i, words[i]);
}
}
int main(){
// This "words" variable is distinct from the one in printWords.
const char *words[] = {"up", "down", "left", "right"};
// It must be passed into printWords along with its size.
printWords(words, 4);
}
ToPigLatingToPigLating function expects to have a parameter like ToPigLating("MyParameter");
Hello there icecolddash.
First things first, there are some concepts missing. In main section:
scanf("%s", word);
You're probably trying to read a string format and store in word variable.
In this case, you should have it on your declaration scope. After some adjustment, it will look like this:
int main(){
char word[LEN];
As you defined LEN with 32 bytes maximum, your program will not be allowed to read bigger strings.
You're also using standard input and output funcitions as printf, and so you should ever include stdio.h, thats the header which cointains those prototypes already declared, avoiding 'implicit declaration' compiling warnings.
Next issue is how you're declaring your translation function, so we have to think about it:
char* ToPigLatin(char* word[LEN])
In this case, what you wrote:
ToPigLatin is a funcion that returns a char pointer, which means you want your function to probably return a string. If it makes sense to you, no problem at all. Although we got some real problem with the parameter char* word[LEN].
Declaring your variable like this, assume that you're passing an array of strings as a parameter. If I got it right, you want to read all five words in main section and translate each one of them.
In this case I suggest some changes in main function, for example :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 32
#define MAX_WORDS 5
char *globalname = "translated";
char* ToPigLatin(char* word){
char *translation = NULL;
//Translation work here.
if ( !strcmp(word, "icecolddash") ){
return NULL;
}
translation = globalname;
return translation;
}
int main(){
char word[LEN];
char *translatedword;
int i;
printf("Enter 5 words: \n");
for ( i=0; i < MAX_WORDS; i++ ){
fgets(word, sizeof(word), stdin);
strtok(word, "\n"); // Just in case you're using a keyboard as input.
translatedword = ToPigLatin(word);
if ( translatedword != NULL ){
//Do something with your translation
//I'll just print it out as an example
printf("%s\n", translatedword);
continue;
}
// Generic couldn't translate message
printf("Sorry, I know nothing about %s\n", word);
}
return 0;
}
The above code translate every word in a fixed word "translated".
In case of reading the exact input "icecolddash", the program will output a generic error message, simulating some problem on translation process.
I hope this help you out with your studies.
There are a few things that I see.
#include <stdio.h>
#include <stdlib.h>
char* ToPigLatin(char* word){
printf(word);
return word;
}
int main(){
printf("Enter 5 words: ");
// declare the variable read into by scanf
char * word = NULL;
scanf("%s", word);
//Pass the variable into the function
ToPigLatin(word);
// Make sure you return an int from main()
return 0;
}
I left some comments in the code with some specific details.
However, the main thing that I would like to call out is the style of the way you're writing your code. Always try to write small, testable chunks and build your way up slowly. Try to get your code to compile. ALWAYS. If you can't run your code, you can't test it to figure out what you need to do.
As for the char ** comment you left on lewis's post, here is some reading you may find useful in building up your intuition:
https://www.tutorialspoint.com/what-does-dereferencing-a-pointer-mean-in-c-cplusplus
Happy coding!
I am just starting to work with functions and wish to read an entire array of user input and convert all entries to uppercase. I am still a little confused how to change things in functions and have the changes occur in the array in the main program.
The code I attached is not working:
Any help and/or explanation would be appreciated.
Thank you
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
// function to turn all user input to uppercase
turnUpCase(char *in,200)
{
char *p;
for (p=in; *p='\0'; ++p)
{
*p = toupper(*p);
}
}
int main(void)
{
char input[200];
int i = 0;
printf("Welcome to the Morse translator.\n");
printf("Enter input: ");
fgets(input, sizeof(input), stdin);
// call to function to turn all input into uppercase
turnUpCase(&input);
return 0;
}
For your turnUpCase function:
1- You are not mentioning any return type.
2- what is 200 ?? write it as retyrn_type turnUpCase(char *p, int size)
in for loop write it as
for (p=in; *p!='\0'; ++p) //to compare with anything use '=='
Name of array is always a pointer. You don't need to mention like turnUpCase(&input). let it go like turnUpCase(input,200)
modify:
turnUpCase(&input); //turnUpCase(input)
turnUpCase(char *in,200) //turnUpCase(char *in)
*p='\0' // *p!='\0'
To make your code work, first you need to change the declaration for turnUpCase() to something like:
void turnUpCase(char *in){}
Since your function does not return a value, it should be declared to be of type void. Next, in the for-loop of the function itself, you have an assignment instead of a comparison. Try this:
for (p = in; *p != '\0'; ++p){}
Finally, when you pass an array to a c function, you are really passing a pointer to the first element of the array, so in your case turnUpCase(input) passes a pointer to the first character of the input string to your function. The way you wrote it, you are passing the address of a pointer to the first character.
Incidentally, I might have written your function like this:
void to_upper(char *str)
{
while(*str) {
*str = toupper(*str);
++str;
}
}
change turnUpCase(&input); to turnUpCase(input); ( an array if passed to a function, "decays" to a pointer to its 1st element, so you don't need to use &) and
also:turnUpCase(char *in,200) to void turnUpCase(char *in) and *p='\0' to *p!='\0'.`
I didn't check if there are the proper libraries for this code to run, but the corrected code seems to be:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
First, we need to declare the method. C needs it inside the header or before the function. Be aware of that this declaration has no body, and ends with ;. After that, we can define the function.
// function to turn all user input to uppercase
void turnUpCase(char *in);
every function needs a return type defined before the definition. Here's the definition and body of the function:
void turnUpCase(char *in) {
char *p;
for (p=in; *p; p++) *p = toupper(*p);
}
Note: As #DavidBowling suggested, this code can be rewritten as (I prefer keeping the original pointer as it was) :
void turnUpCase(char *in) {
char *p = in;
while(*p){
*p = toupper(*p);
p++;
}
}
Both methods check the chars until it reaches a zero char/string end char/null char. Every string in C ends with an \0 (0x00) character, so the function tells that until our string ends, loop the chars and make every char uppercase.
Now the magic begins:
int main(void) {
char input[200];
int i = 0;
printf("Welcome to the Morse translator.\n");
printf("Enter input: ");
fgets(input, sizeof(input), stdin);
Here, you don't need the addressing & operator, because in C, char arrays are already a pointer to it's contents. But, you might give the first char's address to the method too. So there are two options.
First:
// call to function to turn all input into uppercase
turnUpCase(input);
Second:
// call to function to turn all input into uppercase
turnUpCase(&input[0]);
Then, you can print the result to user.
printf("The uppercase version is: %s", input);
return 0;
}
i compile your code with c++ 4.2.1, and it seems has some compilation error.
when you claim a string, input variable is the pointer of first char in string, so it should be turnUpCase(input) when you call the function.
if want to change variable in function, you need to pass pointer or reference into it. in this case, pass input is just fine.
the reason your code not work may be:
for (p=in; *p='\0'; ++p)
should be:
for (p=in; *p=='\0'; ++p)
I am trying to concatenate two strings in C and receive a "Thread 1: signal SIGABRT" error.
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
int main() {
char name[50];
ifile = fopen("stats.list", "r");
for(;;) {
fscanf(ifile, "%s%f%f", name, &sky, &stddev);
if (feof(ifile))
break;
char ext[5] = ".par";
dataparsFile = strcat(name, ext);
dataparsFile = fopen(dataparsFile, "w");
fprintf(dataparsFile, "%s\n",
"stuff gets read in to file named after new string";
fprintf(ofile, "phot ");
fprintf(ofile, "%s%s%s%s%s%s \n",
", datapars=", dataparsFile);
}
fclose(ifile);
fclose(ofile);
The goal of the code is to take an image name that is read in and add on the .par extension. Then, I want to open a file with that name of image+.par and write into it. Since I will have a couple hundred such files, I need to loop through them with the name changing each time.
The problem is name is not initialized. You see, in c strings use a convention, they are any sequence of ASCII (probably some other printable characters, but in principle just ASCII) that must be followed by a '\0' byte that marks the end of the string.
Your name array doesn't have this '\0' so strcat() tries to find it but it fails and perhaps it reads beyond the end of the array, although anyway reading uninitialized data is undefined behavior.
The way strcat(dst, src) works is pretty much like this
char *
strcat(char *const dst, char *src)
{
// Make a pointer to keep dst's address
// unchanged and return it
char *ptr = dst;
// Compute search for the end of the destination
// string to start copying there
while (*ptr != '\0')
ptr++;
// Copy all the characters from `src' until the '\0'
// occurs
while (*src != '\0')
*(ptr++) = *(src++);
*ptr = '\0';
return dst;
}
As you see, this is very inefficient if you call strcat() many times, and it will certainly not work if you pass either of the parameters before initializing it.
In fact, it's terribly unsafe because there is no bound checking, the caller has to make sure that the destination array is large enough to hold both strings.
I have tried to implement the puts function.It in actual returns a value but i cant get what should it return.please check my code and guide me further
/* implementation of puts function */
#include<stdio.h>
#include<conio.h>
void puts(string)
{
int i;
for(i=0; ;i++)
{
if(string[i]=='\0')
{
printf("\n");
break;
}
printf("%c",string[i]);
}
}
See comments in code.
int puts(const char *string)
{
int i = 0;
while(string[i]) //standard c idiom for looping through a null-terminated string
{
if( putchar(string[i]) == EOF) //if we got the EOF value from writing the char
{
return EOF;
}
i++;
}
if(putchar('\n') == EOF) //this will occur right after we quit due to the null terminated character.
{
return EOF;
}
return 1; //to meet spec.
}
And, as an aside - I've written the equivalent of putc, puts several different times in relation to developing on embedded systems. So it's not always just a learning exercise. :)
Comment on EOF: It is a POSIX constant from stdio.h.
In my Linux stdio.h, I have this definition:
/* End of file character.
Some things throughout the library rely on this being -1. */
#ifndef EOF
# define EOF (-1)
#endif
That definition code is GPL 2.1.
From the manual page:
#include <stdio.h>
int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);
int puts(const char *s);
Return Value
fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on error.
puts() and fputs() return a non-negative number on success, or EOF on error.
Well, stdio's puts() returns a non-negative number on success, or EOF on error.
What's string supposed to be? You should define your function better, try:
void my_puts(const char *string)
instead of
void puts(string)
As noted in the link I included, you need to specify the data type of the argument you're passing (in your example string) and you cannot use the name of a function which has already been defined (i.e. puts ).
In addition to what has already been said, I am personally opposed to redefining standard library functions. However, if you absolutely must (e.g. for a homework assignment), and your compiler is complaining about conflicting types for 'puts', try putting this at the top:
#define puts _puts
#include <conio.h>
#include <stdio.h>
#undef puts
I don't see any point in implementing puts!
anyway, you should read the specs of puts so you can make it.
this may help
int myputs(char* s)
{
int x = printf("%s\n", s);
return (x > 0) ? x : EOF;
}
you should include stdio.h so you can use printf and EOF.
Note that this is not EXACT implementation of puts, because on error puts sets an error indicator and do some other stuff.
More details about puts, here.