C easy code with filling array - c

I'm trying to fill an array with a file called data.txt. I don't know what's wrong with code. I get segmentation fault: 11 error.
#include <stdio.h>
#include <stdlib.h>
void input(int arr[]){
FILE* f;
int x, i=0;
f= fopen("data.txt","r");
while (arr[i] != EOF){
fscanf(f,"%d",&x);
arr[i] = x;
i++;
}
fclose(f);
}
int main(){
int arr[50];
input(&arr[50]);
printf("%d", arr[0]);
}

You are reading the number into x (which you are copying into arr[i]) and then comparing arr[i+1] to EOF. That is not how it has to be done.
Try this
while (fscanf(f, "%d", &arr[i]) == 1)
i++;
But this would violate so many safety constraints. Better also bound check and break early if i is greater than some limit, but that limit should be passed to the function.
Another error is with how you are passing arguments to input. Pass input(arr) instead of input(&arr[50]). If you want to use & use input(&arr[0]).

This would be more nearly my version of your code:
#include <stdio.h>
#include <stdlib.h>
static int input(int size, int arr[])
{
const char file[] = "data.txt";
FILE *f = fopen(file, "r");
if (f == NULL)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", file);
exit(EXIT_FAILURE);
}
int i;
for (i = 0; i < size && fscanf(f, "%d", &arr[i]) == 1; i++)
;
fclose(f);
return i;
}
int main(void)
{
int arr[50];
int num = input(50, arr);
for (int i = 0; i < num; i++)
printf("%d: %d\n", i, arr[i]);
return 0;
}
The use of static before the function is necessary to quell -Wmissing-prototypes. The main() function tells the input() function how many elements are in the array so the input() function can avoid overflowing the buffer (a stack overflow, no less). The input() function tells the main() function how many values it read, so the main() function doesn't go accessing data that was not initialized. The crucial function calls are error checked — fopen() and fscanf().
The code compiles cleanly on a Mac running macOS Sierra 10.12.4 using GCC 6.3.0 and the command line below (the source file was rf19.c):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes -Wold-style-definition rf19.c -o rf19
$
I generated a data file with 23 random integers between 10 and 99 in it, and the output was:
$ ./rf19
0: 48
1: 33
2: 77
3: 42
4: 78
5: 51
6: 85
7: 56
8: 55
9: 56
10: 16
11: 38
12: 39
13: 52
14: 34
15: 63
16: 20
17: 23
18: 23
19: 19
20: 39
21: 44
22: 71
$
That's not dreadfully informative, but better than nothing.
The code has deficiencies still, which I don't plan to fix — some more serious than others. For example, the file name is fixed — that's a no-no. The code in the input() function exits on error; that isn't necessarily OK. It produces an error message on standard error — that's better than standard output, but wouldn't be a good idea in a GUI application. The output wastes a lot of horizontal space; with the data shown, you could get 10 values per output line (that would use about 70 characters per line), but the printing for that is more intricate, so I didn't show it. The code treats EOF and a word or punctuation character in the data the same; that might or might not matter, depending on your application. The input simply stops after the 50th entry; maybe you need to know whether there were more entries available to read. I'd probably process the command line arguments as file names, or process standard input if no files were specified — the Unix 'filter command' idiom. I'd probably do something more exciting than just print the first fifty values. I'd probably put the file reading code in a separate function from the file open/close code.

Related

Can not reallocate memory in a very peculiar circumstance

Almost minimal reproducible example:
prog.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *buffer;
int c;
size_t bufsiz = 1024, i = 0;
if (!(buffer = malloc(bufsiz))) {
fputs("malloc() failed!\n", stderr);
return 1;
}
while (EOF != (c = fgetc(stdin))) {
buffer[i] = c;
if (++i == bufsiz && !(buffer = realloc(buffer, bufsiz *= 2))) {
fputs("realloc() failed! (loop)\n", stderr);
return 1;
}
}
buffer[i] = '\0';
if (!(buffer = realloc(buffer, i))) {
fputs("realloc() failed! ", stderr);
fprintf(stderr, "%d\n", i);
return 1;
}
fputs(buffer, stdout);
return 0;
}
I use this command to compile and run:
gcc prog.c -o prog
This command copies the content of prog.c to exp as expected:
cat prog.c | ./prog > exp
This command prints the error message “realloc() failed! 0”:
cat prog.c | ./prog > prog.c
I have yet to find out the reason behind this peculiar behavior...
P.S.: I am using GNU cat and bash
Congratulations, you've (re-)discovered a bug in your system's implementation of realloc, whereby "success" resizing to 0 is indistinguishable from an error. As specified, if realloc returns a null pointer, it has failed and the old object still exists. But some historical implementations treat realloc(p,0) as free(p). Future versions of the C standard allow for this behavior, and deprecate the use of realloc with a zero size, so if you want to use realloc like this you should make sure you are not passing a zero size.
As noted by Eric Postpischil in a comment:
Where does your program put a null character at the end of the string in the buffer?
the fact that 0 is a possible size for your buffer is indicative of a problem - you forgot to reserve space for terminating the string - and if you fix this, even a zero-length string takes a nonzero number of bytes.
In cat prog.c | ./prog > prog.c, the shell parses the command, sees there is a redirection into prog.c, and opens prog.c for writing, which erases any previous contents of the file. Then cat prog.c sees an empty file and copies it to standard output. ./prog faithfully reproduces this empty stream.

how to run my own C program that prints to std out?

I only used C 2-3 times. Following hello world tutorial did not help. the function should just print to std out console.
#include <stdio.h>
void my_putstr(char* param_1) {
char *t ;
for (t = param_1; *t != '\0'; t++) {
printf("%s", t);
}
}
int main(){
my_putstr("abc");
return 0;
}
How to run this program? I do have main to call & test my putstr function.
I do this:
gcc file.c -o file
gcc file
But it still gives me the error of "main":
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
I do have the main function. What's wrong?
gcc file.c -o file
gcc file
That second line will try to compile the executable file that you created with the first line and, since it's not C source(a), that won't end too well :-)
You need to run the file with something like:
./file
And, just as an aside, you should strive to make your programs more readable, such as with:
#include <stdio.h>
// my_putstr:
// Output the given string multiple times, each time starting
// at the next character. So, for "1234", it would output
// "1234 234 34 4" (without the spaces).
void my_putstr(char *str) {
// Start at position 0, 1, m2, etc until no more string left.
for (char *ptr = str; *ptr != '\0'; ptr++) {
printf("%s", ptr);
}
}
int main(void) {
my_putstr("abc");
return 0;
}
Changes made:
Comments are quite handy if you ever come back to the code after some time;
You should try to avoid simple variable names, use names that make the intent clear (about the only exception are simple i, j, k loop variables;
The two canonical forms of main are int main(int argc, char **argv) (though the "or equivalent" phrase in the standard also allows for int main(int argc, char *argv[])) or int main(void), you should try to stick with them.
By the way, the description in the comments above is an accurate representation of the way the code works. If, instead, you just want to output a string (i.e., not the 1234 234 34 4 behaviour), you're probably better off with something like:
void my_putstr(char *str) {
// Output each character, one at a time.
for (char *ptr = str; *ptr != '\0'; ptr++)
putchar(*ptr);
// Output newline (if desired).
putchar('\n');
}
(a) The gcc program is quite capable of taking other input file types (like object files, assembler files, and so on) but I'm not sure finished executables are one of those types.

Change something in C program with Shell Script

Is it possible to write a script to run this code for different values of A;
#include <stdio.h>
#define A 3
int main (){
printf("In this version A = %d\n", A);
return(0);
}
I guess something like for loop?
Is it possible to write a script to run this code for different values of A;
Not as it is because the macro A has a fixed value defined in your code. Instead you can pass the value as an argument:
#include <stdio.h>
int main(int argc, char **argv){
if(argc == 2) {
printf("In this version A = %s\n", argv[1]);
}
return 0;
}
(The code doesn't check if its input is an integer -- which you can test if necessary).
and you can run it via script. For example, compile the above (gcc -Wall -Wextra test.c -o test) using a for loop of bash:
$ for ((i = 0; i < 10; i++)); do ./test $i; done
In this version A = 0
In this version A = 1
In this version A = 2
In this version A = 3
In this version A = 4
In this version A = 5
In this version A = 6
In this version A = 7
In this version A = 8
In this version A = 9
$
No. But you can make A a command line arg:
#include <stdio.h>
int main (int argc, char *argv[]) {
int a;
if (argc != 2 || sscanf(argv[1], "%d", &a) != 1) return 1;
printf("In this version A = %d\n", a);
return 0;
}
Compile to a binary named foo, then
foo 42
will print
In this version A = 42
You can also compile different versions by defining A in the compilation command line. From your original program, remove the #define. Then
gcc -DA=42 foo.c -o foo
./foo
will print the same as above.
DO you need run program repeated from script? why not to make program that accepts arguments from command line?
1)The main() function actually takes arguments, you can compile program once and pass different parameters, as shown in answers above
2) If you need to change some code parameters from make script, I'd say, create separate header that would contain defines and write script that would echo into that file (> for start, >> to continue writing).
3) Alternative way you can call you compiler with flag that would be equal to #define macro-command. For gcc it's -D, for example -DA=3 instead of #define A 3.
Most programs use makefile to be compiled. For that case you can script make file to use 2) or 3) Former is preferable because you do not need to pass that argument to all compilation targets, reducing time or re-compiling. There are tools for more advanced manipulations, like autoconf.

Unescape a universal character name to the corresponding character in C

NEW EDIT:
Basically I've provided a example that isn't correct. In my real application the string will of course not always be "C:/Users/Familjen-Styren/Documents/V\u00E5gformer/20140104-0002/text.txt". Instead I will have a input window in java and then I will "escape" the unicode characters to a universal character name. And then it will be "unescaped" in C (I do this to avoid problems with passing multibyte characters from java to c). So here is a example where I actually ask the user to input a string (filename):
#include <stdio.h>
#include <string.h>
int func(const char *fname);
int main()
{
char src[100];
scanf("%s", &src);
printf("%s\n", src);
int exists = func((const char*) src);
printf("Does the file exist? %d\n", exists);
return exists;
}
int func(const char *fname)
{
FILE *file;
if (file = fopen(fname, "r"))
{
fclose(file);
return 1;
}
return 0;
}
And now it will think the universal character names is just a part of the actual filename. So how do I "unescape" the universal character names included in the input?
FIRST EDIT:
So I compile this example like this: "gcc -std=c99 read.c" where 'read.c' is my source file. I need the -std=c99 parameter because I'm using the prefix '\u' for my universal character name. If I change it to '\x' it works fine, and I can remove the -std=c99 parameter. But in my real application the input will not use the prefix '\x' instead it will be using the prefix '\u'. So how do I work around this?
This code gives the desired result but for my real application I can't really use '\x':
#include <stdio.h>
#include <string.h>
int func(const char *fname);
int main()
{
char *src = "C:/Users/Familjen-Styren/Documents/V\x00E5gformer/20140104-0002/text.txt";
int exists = func((const char*) src);
printf("Does the file exist? %d\n", exists);
return exists;
}
int func(const char *fname)
{
FILE *file;
if (file = fopen(fname, "r"))
{
fclose(file);
return 1;
}
return 0;
}
ORIGINAL:
I've found a few examples of how to do this in other programming languages like javascript but I couldn't find any example on how to do this in C. Here is a sample code which produces the same error:
#include <stdio.h>
#include <string.h>
int func(const char *fname);
int main()
{
char *src = "C:/Users/Familjen-Styren/Documents/V\u00E5gformer/20140104-0002/text.txt";
int len = strlen(src); /* This returns 68. */
char fname[len];
sprintf(fname,"%s", src);
int exists = func((const char*) src);
printf("%s\n", fname);
printf("Does the file exist? %d\n", exists); /* Outputs 'Does the file exist? 0' which means it doesn't exist. */
return exists;
}
int func(const char *fname)
{
FILE *file;
if (file = fopen(fname, "r"))
{
fclose(file);
return 1;
}
return 0;
}
If I instead use the same string without universal character names:
#include <stdio.h>
#include <string.h>
int func(const char *fname);
int main()
{
char *src = "C:/Users/Familjen-Styren/Documents/Vågformer/20140104-0002/text.txt";
int exists = func((const char*) src);
printf("Does the file exist? %d\n", exists); /* Outputs 'Does the file exist? 1' which means it does exist. */
return exists;
}
int func(const char *fname)
{
FILE *file;
if (file = fopen(fname, "r"))
{
fclose(file);
return 1;
}
return 0;
}
it will output 'Does the file exist? 1'. Which means it does indeed exist. But the problem is I need to be able to handle universal character. So how do I unescape a string which contains universal character names?
Thanks in advance.
I'm reediting the answer in the hope to make it clearer. First of all I'm assuming you are familiar with this: http://www.joelonsoftware.com/articles/Unicode.html. It is required background knowledge when dealing with character encoding.
Now I'm starting with a simple test program I typed on my linux machine test.c
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#define BUF_SZ 255
void test_fwrite_universal(const char *fname)
{
printf("test_fwrite_universal on %s\n", fname);
printf("In memory we have %d bytes: ", strlen(fname));
for (unsigned i=0; i<strlen(fname); ++i) {
printf("%x ", (unsigned char)fname[i]);
}
printf("\n");
FILE* file = fopen(fname, "w");
if (file) {
fwrite((const void*)fname, 1, strlen(fname), file);
fclose(file);
file = NULL;
printf("Wrote to file successfully\n");
}
}
int main()
{
test_fwrite_universal("file_\u00e5.txt");
test_fwrite_universal("file_å.txt");
test_fwrite_universal("file_\u0436.txt");
return 0;
}
the text file is encoded as UTF-8. On my linux machine my locale is en_US.UTF-8
So I compile and run the program like this:
gcc -std=c99 test.c -fexec-charset=UTF-8 -o test
test
test_fwrite_universal on file_å.txt
In memory we have 11 bytes: 66 69 6c 65 5f c3 a5 2e 74 78 74
Wrote to file successfully
test_fwrite_universal on file_å.txt
In memory we have 11 bytes: 66 69 6c 65 5f c3 a5 2e 74 78 74
Wrote to file successfully
test_fwrite_universal on file_ж.txt
In memory we have 11 bytes: 66 69 6c 65 5f d0 b6 2e 74 78 74
Wrote to file successfully
The text file is in UTF-8, my locale is working of of UTF-8 and the execution character set for char is UTF-8.
In main I call the function fwrite 3 times with character strings. The function prints the strings byte by byte. Then writes a file with that name and write that string into the file.
We can see that "file_\u00e5.txt" and "file_å.txt" are the same: 66 69 6c 65 5f c3 a5 2e 74 78 74
and sure enough (http://www.fileformat.info/info/unicode/char/e5/index.htm) the UTF-8 representation for code point +00E5 is: c3 a5
In the last example I used \u0436 which is a Russian character ж (UTF-8 d0 b6)
Now lets try the same on my windows machine. Here I use mingw and I execute the same code:
C:\test>gcc -std=c99 test.c -fexec-charset=UTF-8 -o test.exe
C:\test>test
test_fwrite_universal on file_å.txt
In memory we have 11 bytes: 66 69 6c 65 5f c3 a5 2e 74 78 74
Wrote to file successfully
test_fwrite_universal on file_å.txt
In memory we have 11 bytes: 66 69 6c 65 5f c3 a5 2e 74 78 74
Wrote to file successfully
test_fwrite_universal on file_╨╢.txt
In memory we have 11 bytes: 66 69 6c 65 5f d0 b6 2e 74 78 74
Wrote to file successfully
So it looks like something went horribly wrong printf is not writing the characters properly and the files on the disk also look wrong.
Two things worth noting: in terms of byte values the file name is the same in both linux and windows. The content of the file is also correct when opened with something like notepad++
The reason for the problem is the C Standard library on windows and the locale. Where on linux the system locale is UTF-8 on windows my default locale is CP-437. And when I call functions such as printf fopen it assumes the input is in CP-437 and there c3 a5 are actually two characters.
Before we look at a proper windows solution lets try to explain why you have different results in file_å.txt vs file_\u00e5.txt.
I believe the key is the encoding of your text file. If I write the same test.c in CP-437:
C:\test>iconv -f UTF-8 -t cp437 test.c > test_lcl.c
C:\test>gcc -std=c99 test_lcl.c -fexec-charset=UTF-8 -o test_lcl.exe
C:\test>test_lcl
test_fwrite_universal on file_å.txt
In memory we have 11 bytes: 66 69 6c 65 5f c3 a5 2e 74 78 74
Wrote to file successfully
test_fwrite_universal on file_å.txt
In memory we have 10 bytes: 66 69 6c 65 5f 86 2e 74 78 74
Wrote to file successfully
test_fwrite_universal on file_╨╢.txt
In memory we have 11 bytes: 66 69 6c 65 5f d0 b6 2e 74 78 74
Wrote to file successfully
I now get a difference between file_å and file_\u00e5. The character å in the file is actually encoded as 0x86. Notice that this time the second string is 10 characters long not 11.
If we look at the file and tell Notepad++ to use UTF-8 we will see a funny result. Same goes to the actual data written to the file.
Finally how to get the damn thing working on windows. Unfortunately It seems that it is impossible to use the standard library with UTF-8 encoded strings. On windows you can't set the C locale to that. see: What is the Windows equivalent for en_US.UTF-8 locale?.
However we can work around this with wide characters:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#define BUF_SZ 255
void test_fopen_windows(const char *fname)
{
wchar_t buf[BUF_SZ] = {0};
int sz = MultiByteToWideChar(CP_UTF8, 0, fname, strlen(fname), (LPWSTR)buf, BUF_SZ-1);
wprintf(L"converted %d characters\n", sz);
wprintf(L"Converting to wide characters %s\n", buf);
FILE* file =_wfopen(buf, L"w");
if (file) {
fwrite((const void*)fname, 1, strlen(fname), file);
fclose(file);
wprintf(L"Wrote file %s successfully\n", buf);
}
}
int main()
{
test_fopen_windows("file_\u00e5.txt");
return 0;
}
To compile use:
gcc -std=gnu99 -fexec-charset=UTF-8 test_wide.c -o test_wide.exe
_wfopen is not ANSI compliant and -std=c99 actually means STRICT_ANSI so you should use gnu99 to have that function.
Wrong array size (forgot the .txt and \0 and that an encoded non-ASCII char takes up more than 1 byte.)
// length of the string without the universal character name.
// C:/Users/Familjen-Styren/Documents/Vågformer/20140104-0002/text
// 123456789012345678901234567890123456789012345678901234567890123
// 1 2 3 4 5 6
// int len = 63;
// C:/Users/Familjen-Styren/Documents/Vågformer/20140104-0002/text.txt
int len = 100;
char *src = "C:/Users/Familjen-Styren/Documents/V\u00E5gformer/20140104-0002/text.txt";
char fname[len];
// or if you can use VLA
char fname[strlen(src)+1];
sprintf(fname, "%s", src);

About Linux C - UUID

#include <stdio.h>
#include <stdlib.h>
#include <uuid/uuid.h>
int main(void) {
puts("!!!Hello World!!!"); /* prints !!!Hello World!!! */
uuid_t uuid;
int uuid_generate_time_safe(uuid);
printf("%x",uuid);
return EXIT_SUCCESS;
}
I just wonder why uuid is not 16 bytes long?
I use DEBUG to view the memory, It is indeed not 16 bytes.
And I use libpcap to develop my program, The uuid is not unique.
I just tried your program on my system, and uuid is 16 bytes long. But your program doesn't display its size.
The line:
int uuid_generate_time_safe(uuid);
isn't a call to the uuid_generate_time_safe function, it's a declaration of that function with uuid as the (ignored) name of the single parameter. (And that kind of function declaration isn't even valid as of the 1999 standard, which dropped the old "implicit int" rule.)
Your printf call:
printf("%x",uuid);
has undefined behavior; "%x" requires an argument of type unsigned int.
If you look in /usr/include/uuid/uuid.h, you'll see that the definition of uuid_t is:
typedef unsigned char uuid_t[16];
The correct declaration of uuid_generate_time_safe (see man uuid_generate_time_safe) is:
int uuid_generate_time_safe(uuid_t out);
You don't need that declaration in your own code; it's provided by the #include <uuid/uuid.h>.
Because uuid_t is an array type, the parameter is really of type unsigned char*, which is why the function is seemingly able to modify its argument.
Here's a more correct program that illustrates the use of the function:
#include <stdio.h>
#include <uuid/uuid.h>
int main(void) {
uuid_t uuid;
int result = uuid_generate_time_safe(uuid);
printf("sizeof uuid = %d\n", (int)sizeof uuid);
// or: printf("sizeof uuid = %zu\n", sizeof uuid);
if (result == 0) {
puts("uuid generated safely");
}
else {
puts("uuid not generated safely");
}
for (size_t i = 0; i < sizeof uuid; i ++) {
printf("%02x ", uuid[i]);
}
putchar('\n');
return 0;
}
On my system, I got the following output:
sizeof uuid = 16
uuid not generated safely
26 9b fc b8 89 35 11 e1 96 30 00 13 20 db 0a c4
See the man page for information about why the "uuid not generated safely" message might appear.
Note that I had to install the uuid-dev package to be able to build and run this program.

Resources