c fgets char array - c

I have a problem with fgets. I can't save the String "temp" in the if-statement.
The Code:
1 #include <stdio.h>
2 #include <string.h>
3 #include<stdlib.h>
4
5 void moep(char** tmp){
6 FILE *fp;
7 fp=fopen("moep", "r");
8 int line_num = 1;
9 int find_result = 0;
10 char* str="jochen";
11 char temp[512];
12
13 while(fgets(temp, 512, fp) != NULL) {
14 if((strstr(temp, str)) != NULL) {
15 printf("A match found on line: %d \n", line_num);
16 tmp[find_result]=temp;
17 printf("\n%s\n", tmp[find_result] );
18 find_result++;
19 }
20 line_num++;
21 }
22 fclose(fp);
23 printf("tmp[0]:%s\n",tmp[0]);
24 tmp[1]="ich funktioniere";
25 }
26
27 int main(){
28
29 char* tmp[1];
30 moep(tmp);
31 printf("%s, %s\n",tmp[0],tmp[1]);
32 return 0;
33 }
and moep is:
unwichtig1
jochen g
unwichtig2
unwichtig3
The output:
/A match found on line: 2
jochen g
tmp[0]:unwichtig3
��Ł�, ich funktioniere
why can't I save "jochen" in tmp[0]?

Assigning to tmp[1] is assigning to random memory, as you're array isn't that big.
It will have all sorts of bad side effects - including crashing the program.
You are also reusing the temp[] array - so that will keep getting overwritten, you need to copy the string if you want to keep it.

There are several problems. I did not look at moep() at all, only main().
You probably did not intended to declare tmp as:
char* tmp[1];
This declares a pointer, but does not point anywhere. Accessing the second element in it is not "kosher" because it is declared to be one element. (But it doesn't matter because the array is not allocated.)
Probably you meant
char tmp[2];
This allocates a space for two characters.

It's a bit of a mess.
temp is an array of pointers to char. You assign the pointer to temp to the first, second etc. element of that array. That said, this is always the same value, since temp itself doesn't change, and it's contents gets overwritten every iteration of the loop.
Use strncpy() to copy from one string to another.

Related

How do I hold hexidecimal letter values in an int? [C]

I am writing a cache lab in C and I have got the whole input file to print in a char array, but any and all help for my cache lab online uses int to hold the input file, so I am thinking I need that too.
I have a three input files. One holds:
10
20
22
18
E10
210
12
I can get 10, 20, 22, 18 to print:
FILE* file;
int address;
file = fopen("address01" , "r");
while (fscanf(file, "%d", &address)) {
printf("%d\n", address);
}
fclose(file);
but it stops after 18 since the next input is a char. I know characters can be held as an int on their own, so how can I also do this with the E and the 10 being together?
You can use the %x format specifier to read hexadecimal values into an int. For example:
int address;
if (fscanf(file, "%x", &address) == 1) {
printf("%d\n", address);
}
This will read the hexadecimal value E10 into the int variable address.

C character array comparison

Ok so I was doing a coding challenge on codewars.com and the challenge was to take a string as input and return a string where in place of the letters are instead the number of the alphabet that matches the letter.
Everything except letters are to be ignored.
ex: "aab" would return "1 1 2"
There should be a space between each number that represents a letter in the alphabet.
So, when I run this code on my IDE (which is xcode using c99) Everything looks good and the strcmp() function says the 2 strings are equal.
The website I'm on uses C11 I believe but I don't see that causing the error.
When I run this code on the challenge website it passes a couple of tests but then fails a couple also. It fails when the input string is "", and it also fails on the string that I have used in the code below, but again it does not fail when I run it on my ide.
My questions are:
1) Any idea what is causing this bug?
2) What would you have done differently as far as the code is concerned
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *alphabet_position(char *text)
{
int i,letter_position;
unsigned long int size = strlen(text);
char *result = malloc(sizeof(int)*size + 1);
char int_string[10];
char temp = ' ';
//If String wasn't blank
if (strcmp(text, "")!=0)
{
for (i=0; i<size-1; i++)
{
//If it is a letter
if (isalpha(text[i]))
{
temp = tolower(text[i]);
if (temp == 'a')
strcat(result, "1");
else
{
letter_position = temp - 'a' + 1;
sprintf(int_string,"%d",letter_position);
strcat(result, int_string);
}
//Print space after letter until the last letter
if (i!=size-2)
strcat(result, " ");
}
}
strcat(result, "\0");
return result;
}
else
{
strcat(result, "\0");
return result;
}
}
int main(void)
{
char *string = alphabet_position("The narwhal bacons at midnight.");
char *expected_output = "20 8 5 14 1 18 23 8 1 12 2 1 3 15 14 19 1 20 13 9 4 14 9 7 8 20";
printf("Your output %s\n", alphabet_position("The narwhal bacons at midnight."));
printf("Expt output %s\n", "20 8 5 14 1 18 23 8 1 12 2 1 3 15 14 19 1 20 13 9 4 14 9 7 8 20");
printf("\n");
printf("your len %lu\n", strlen(alphabet_position("The narwhal bacons at midnight.")));
printf("Expt len %lu\n", strlen(expected_output));
if (strcmp(string, expected_output)==0)
printf("Equal\n");
else
printf("Not equal\n");
return 0;
}
You have two serious problems.
First, you're not initializing the contents of the result array to an empty string. After you call malloc(), add:
result[0] = '\0';
malloc() doesn't initialize the memory it allocates. There's another function calloc() that takes slightly different arguments and initializes the memory to zeroes. But you only need the first character to be zero, so there's no need for that.
Second, the for loop is not processing the last character of text. It should be:
for (i = 0; i < size; i++)
Similarly, the test for whether to add a space should be if (i != size-1). Did you think strlen() counts the null character at the end?
The amount of space you specify in malloc() is not correct, but in practice it won't cause a problem. sizeof(int) has nothing to do with the number of characters it takes to show the value of an integer. Since you're just printing the alphabetical position, it will be at most 26, so you need 3 characters for every input character. Therefore, it should be:
char *result = malloc(3 * size + 1);
Your allocation works because sizeof(int) is generally at least 4, so you're allocating more than enough space.
There are other minor problems that don't affect the correctness of the result:
You don't need the if statement that treats 'a' specially, the code you have in else will work for all letters.
You don't need strcat(result, "\0") at the end. result has to already be null-terminated in order for you to use it as an argument to strcat(), so there's no point in using strcat() to add a null terminator.

Reading the first line of a txt and converting it to int, but returning another value [C]

I've been trying to read a txt which has a specific structure:
The first line indicates the n-1 lines the whole txt file has.
All the other lines have the "structure" of a card (it's number and it's pattern).
ex: I have a txt which stores 13 cards, so the file in itself has 14 lines:
13
A T
2 P
3 D
13 P
2 P
4 C
8 D
11 T
8 C
9 C
10 T
9 T
7 P
(Note: T stands for clubs, D for diamonds, C for hearts and P for spades, it's in spanish).
I've tried extracting the first line to then create a dynamic array with the number given so that I can store each line in that array, but I fail to get the first value.
My code is:
#include <stdio.h>
#include <stdlib.h>
int leerLinea(){
char contenido[1];
FILE* pArchivo;
pArchivo = fopen("Mazo.txt","r");
if (pArchivo == NULL){
printf("No hay nada aqui!\n");
return 0;
}
else{
fgets(contenido,3,pArchivo);
printf("%s\n", contenido);
}
fclose(pArchivo);
return contenido[0];
}
int main(){
int a;
a = leerLinea();
printf("a's value is: %d\n",a);
return 0;
}
But when I run it I get:
13
a's value is: 49
Why is it returning other value, when it should be returning 13?
With fgets(contenido,3,pArchivo), you read in a string into a buffer that is to small for capturing at least 2 digits and the string termination character; For that statement, it should be at least char contenido[3].
The main issue is, however, that you mix strings with "pure" integral values, i.e. you read in a string but expect it to be converted correctly to a number simply by accessing the first digit of that string; Note that if contenido containded "13", contenido[0] would give character value '1', which in ASCII is 49.
To overcome this, read in the value as a number, i.e. using "%d"-format:
int leerLinea(){
int contenido = 0;
FILE* pArchivo;
pArchivo = fopen("Mazo.txt","r");
if (pArchivo == NULL){
printf("No hay nada aqui!\n");
return 0;
}
else{
fscanf(pArchivo,"%d",&contenido);
printf("%d\n", contenido);
}
fclose(pArchivo);
return contenido;
}
1 - Read a line of text with sufficient space for each character in the line, the line-feed and a null character. The below is 4 characters, so a buffer of 6 is needed.
13 P
Further, there is little gained by being so stingy with line buffers. Suggest 2x the maximize anticipated size to allow for some growth, leading/trailing whitespace.
#define LINE_MAX (4 + 1 + 1)
char contenido[LINE_MAX * 2];
2 - When reading a line, do not hard code in the 3, use sizeof() for consistent, easier to maintain code.
// fgets(contenido,3,pArchivo);
fgets(contenido, sizeof contenido, pArchivo);
3 - Rather than return the first character of a string (the code for the character '1' is 49), convert the string into an int/long with strtol() or atol(), etc. #Nicolas Guerin
// return contenido[0];
return atoi(contenido);
// or
return strtol(contenido, NULL, 10); // better
return atoi(contenido[0]);
The probleme you've got is that you return a char in an int function, every char as an integer value. That's true but not the decimal value of the char, the ascii value.
Atoi convert a char into an int.
ps: the way you do, it will only return 1 in the exemple

Wrote a program to view binary data. Did I do this correctly or am I getting junk data?

My assignment this week is to go create a program that reads a data file that my professor sent to me. The assignment says there are 10 integers in this data that I need to write to an array, which I've done but I'm not sure if it's correct or just junk data. I will attach the a DL link for this file (it's only 40bytes). I've created a program below that will read off the 10 numbers that I need, but how do I know if it is junk data or the real deal. I am getting the same numbers everytime, is that an indication that I'm doing this correctly? Any long term tips for me to use in the future would be appreciated as well.
Here is the DL link
mysteryData
#include <stdio.h>
#include <string.h>
int main(void)
{
int i;
FILE* myFile = NULL;
myFile = fopen("mysteryData.dat", "rb");
int Mystery[10] =
{ '\0' };
if (myFile == NULL )
{
printf("Failed to open file\n");
}
else
{
fread(Mystery, sizeof(int), sizeof(Mystery), myFile);
printf("%d\n", Mystery);
}
for (i = 0; i < 9; i++)
{
printf("%d\n", Mystery[i]);
}
fclose(myFile);
}
First, if you mean to print the address of Mystery after the fread call, you should use %p. Second, perhaps printing in hex will help you see the problem:
% echo $'\x12\x34\x56\x78\x9a\xbc\xde\xff' > mysteryData.dat
% ./test
0x7fff598cfae0 # %p
78563412 # %x
ffdebc9a
a # newline = 0x0a
0
0
0
0
0
0
%
The values are being strung together in the integers, and are bytewise-reversed. They are being strung together because you are reading them as integers:
12 34 56 78 9a bc de ff a0 00 00 00
^---------^ ^---------^ ^---------^
From this we see that ints in my compiler are 32 bits (4 bytes). Furthermore, the reason the bytes are swapped is because my system is little-endian; that means that the 12 is the least significant 8 bits, 34 is the next most significant, etc.
You probably want to access these as individual bytes, for which you should change Mystery to a char[10]. And maybe make it bigger to ensure you have enough space. Finally, you want to check the return value of fread, which will tell you how many bytes you have actually read.
Fread is declared thusly:
fread(void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
^^^^ ^^^^^^
You are passing the right size, but instead of passing the number of items for nitems, you are passing the size of Mystery, which is nitems*sizeof(int). Use
fread(Mystery, sizeof(int), sizeof(Mystery)/sizeof(int), myFile);
Or better,
fread(Mystery, sizeof(Mystery[0]), sizeof(Mystery)/sizeof(Mystery[0]), myFile);
First of all it should specified how these integers are stored into the file.
As the file is 40 bytes and there is a specification that the count of items is 10 you can assume that they are stored as binary data and each integer takes four bytes.
*I say that because the file may be a text file with integers stored as newline separated values:
10
13
4563
-32
etc......
But. In 40 bytes there is no space for 10 integers stored as text, so let's say they are in binary data.
At this point we assume also that the endianess of the data is the same of the architecture your program will be compiled and run. I won't go further on this, for more info you may google for big endian little endian
Finally it should be specified what is the size of an integer. The size of an integer may vary depending on the OS / architecture:
see What does the C++ standard state the size of int, long type to be?
But we have 40 bytes, we know we have 10 ints. Into the file the int is 4 bytes for each number.
You may check if that match with your architecture with:
printf("Here ints are %d bytes.\n", (int) sizeof(int));
and looking at the output.
Going back to your code thare are some things to be adjusted. See the comments...
#include <stdio.h>
#include <string.h>
int main (void)
{
int i;
int itemsRead; // we'll use that later...
FILE* myFile=NULL;
myFile=fopen("mysteryData.dat", "rb");
int *Mystery = malloc (sizeof(int) * 10); // It's a better practice...
//... to allocate the buffers/arrays you need instead of declaring them
// statically. If your file grows up with millions of numbers your code
// will still be scalable.
if(!Mystery) // Just check the alloc succeeded
{
printf("Failed to allocate buffer\n");
}
if(myFile==NULL)
{
printf("Failed to open file\n");
free( Mystery ); // Free the buffer
return 0; // Quit
}
itemsRead = fread(Mystery, sizeof(int), 10, myFile);
// 2nd parameter is size of element
// 3rd parameter is how many items
// the function returns the items actually read
// What is the file was shorter than expected?
// Check we were able to actually read 10 items of 4 bytes each
if( itemsRead < 10 )
{
printf("The file ended unexpectedly\n");
free( Mystery ); // Free the buffer
return 0; // Quit
}
for (i=0; i<10; i++) // 10 Items: count from 0 to 9 so until i<10
{
printf("%d\n", Mystery[i]);
}
free( Mystery );
fclose( myFile );
}

Byte allocation in short unsigned data

kindly check the following program
#include <stdio.h>
#include<stdlib.h>
int main()
{
char *Date= NULL;
unsigned short y=2013;
Date = malloc(3);
sprintf((char *)Date,"%hu",y);
printf("%d %d %d %d %d \n",Date[0],Date[1],Date[2],Date[3],Date[4]);
printf("%s %d %d",Date,strlen(Date),sizeof(y));
}
output:
50 48 49 51 0
2013 4 2
How I am getting the string length 4 instead 2,as I am putting a short integer value into the memory so it should be occupied in 2 byte of memory.But how it is taking 4 byte.
How each byte getting 2 0 1 3 from the input, instead 20 in one byte and 13 in another byte.
I want to put 20 to one byte and 13 to another byte.How to do that.kindly tell something
Kindly give some answer.
As indicate by its name, the sprintf function write a formated string. So, your number 2013 is converted to "2013" (a 5 character string).
You are invoking undefined behaviour.
You have allocated only 3 bytes for Date and storing 5 bytes.
Four bytes for 2013 and 1 NUL byte. So you should allocate at least 5 bytes if you want to store 2013.
If you want to transfer a stream of bytes then I suggest you do in the following way:
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
unsigned char *Date= NULL;
unsigned short y=2013;
unsigned char *p;
p = (unsigned char*) &y;
Date = malloc(3);
Date[0] = *p;
Date[1] = *(p+1);
Date[2] = 0;
printf("%s %d %d",Date,strlen(Date),sizeof(y));
}
This outputs:
� 2 2
The strange char is because interpreting some byte values as a string. Plain char may be signed or unsigned depending on your implementation. So use unsigned char to avoid incorrect interpretation of bytes.

Resources