Skip to main content

Interaction with users in C

 INTERACTING WITH USER AND SYSTEM

1. Operating System

-Most interesting interactions that read inputs and write a file require access to hardware devices. It requires the permission from permissions system. 

-The program asks the operating system to access hardware. It makes the request via a system call. It transfer control from the program into the operating system. The operating system checks that the program's request is within the bounds of its permissions before performing it.

-It's more common to use functions in the C library than system calls.

-printf is not part of the C library and includes significant code which does not require system calls. BUT it does contain a system call in some cases. It is not correct to cal printf a system call.

2. Errors in System Calls

-Errors include: read a file that does not exist or does not have permissions for. 

-Whenever system calls fails, their wrapper in the C library set a global variable called 'errno'.

-To know why the call failed, we can compare it against the various constants defined in errno.h. Or we can refer to 'perror', which resides in C library and will print a edscriptive error message based on the current value of errno.

-We should not call anything that might cause 'errno' to change before we call 'perror'.

3. Command Line Arguments

-One type of input our programs can take is command line arguments. For example, in "gcc -o hello hello.c" we are passing the arguments: name(gcc)  to GCC. However,  we don't generally think its name to be one arguments. 

4. Command Line Arguments

-In gcc -o myProgram mypRogram.c, -o option itselfe takes an argument: the next command line argument (In this command line, myProgram)after it. 

-'getopt' function parses the command line arguments, accounting for such considerations as options that have arguments, as well as short and long name versions. (e.g. -o and --output are the same but difference is that one is long and one is short)

5. Environment Pointer

-'main' can  take a third argument: char**envp, a pointer to an array of strings containing the value of environment variables. 

-If you include this, th elements of the array are strings of the form variable=value (PATH=/bin:/usr/bin).  We can also access environment variables using the function getenv, setenv, putenv, and unsetenv.

6. Process Creation

-When the command shell wants  to run another program, it makes several system calls. First, it makes a call to create a new process. The new process then makes another system call (execve) to replace its running program with the requested program. The execve system call takes the file with binary to run. A second argument pass the new program as argv and a third argument specifying the values to pass for envp. 

-execve -> destroy currently running program -> write argv and envp -> set execution arrow to start location -> startup ocde calls various functions that initialize C library 

-When main returns, it returns to the function that called it. It is the startup code that calls it. Then this code performs any cleanup required by the C library and calls exit, passing in the return value of main as the argument of exit. 

6. Files

-Opening a file causes a stream associated with the file. A stream is a sequence of data that can be read and written. 

-We can use fopen function to open a file. The prototype of fopen is:
FILE * fopen (const char * filename, const char *mode);

-It takes two arguments, the first is the pathname of the file to open.  It can either be an absolute path, or a path relative to the current working directory. 

-The second argument is the mode of the file: Whether the file should be opened for reading or writing, whether to create a file if it does not exist, whether existing content is cleared out, etc. 

-Real FILE structs do not contain the name of the file, but rather a file descriptor -- a numeric identifier returned to the program by the operating system.

-It's possible for fopen to fail when the file requested does not exist, or does not have the permissions required to access it. Whenever it fails, it returns NULL, and sets errno appropriately. We should check the return value of fopen before we attemp to use the stream.

Modes for fopen:
mode    read and/or write    does not exist?    truncate?    position
r              read only                    fails                    no            begining
r+           read/write                    fails                    no            begining
w            write only                  created                yes            begining
w+          read/write                  created                yes            begining
a               writing                     created                 no                end
a+            read/write                created                  no                end

7. Reading Files

-We can use one of three functions to read files: fgetc, fgets, fread. fgetc is useful when you want to read one character at a time.

-fgetc returns an int so that it can return all possible chars plus a distinct value  to indicate the end of file has been reached. The value for end-of-file is defined as the constant EOF in stdio.h.

FILE * f = fopen(inputfilename,"r");
if(f==NULL){}
while(fgetc(f) != EOF) {
    char c  = fgetc(f);    //evaluate to fgetc(f)
    printf("%c", c);
}

or 

FILE * f = fopen(inputfilename,"r");
if(f==NULL){}
while(c=fgetc(f) != EOF) {
    printf("%c", c);
}

-fgets is useful when you want to read one line. It has the following prototype:
char * fgets(char * str, int size, FILE * stream);

-It will write data into str[0], str[1], str[2] and so on. The second argument specifies the size of the array str. The final argument specifies what stream to read the data. 

-It returns str if it succeeds. The data in str is null-terminated. It returns NULL if it fails. We can use feof and ferror to specify if it meets EOF or some other errors. 

-We should never use 'gets'. This function will continue to read data until it reaches a newline. This function therefore poses a significant security vulnerability. 

-When we want to read data from image, video, sound or other file, the most appropriate function is fread. The prototype of fread is as following:
size_t fread (void * ptr, size_t size, size_t nitems, FILE * stream);

-The first argument is a pointer to the data to write. The next one is the size of each item. The third argument specifies how many such items should be read from the stream and the final argument specifies which stream to read. fread returns how many items were successfully read. 

-We can use feof and ferror to obtain more information if it returns fewer items than we requested.

- We can use fscamf tp read formatted input. It will stop reading input as soon as it encounters something that does not match the requested format. 

8. Writing Files

-fprintf function is useful when we want to print formatted text. It performs same as printf function, except that it takes and additional argument: FILE* to specifying where to write the output. 

-We can also use fputc to write a single character at a time or use fputs to write a string without format conversions. It means, if we do fputs("%d"), it will print %d directly, rather than attempting to convert and integer and print it.

-We can use fwrite to print non-textual data. 

9. Closing Files

-After finishing with a file, we should close it with fclose function. Prototype is following:
int fclose(FILE * stream);

-Closing the stream sends any buffered write data to OS and then asks the OS to close the associated file descriptor. After closing it, we may no longer access it. (i.e. using fgetc, fprintf, etc.)

-fclose returns an int. It indicates the success or failure. It can fail when the disk is full, or the file resides on a remote file system and network connectivity has been lost. Failure of fclose is a serious situation. It means the data your program tries to write may be lost. So, we should always check the return value of fclose to see if it fails or not.

-When fclose fails, we should not perform any operation on the stream, including another call to fclose. What we should do depends. 

summary& understanding  after reading <<All of Programming>> chapter 11

Comments

Popular posts from this blog

Templates

  Template - Polymorphism is the ability of the same code to operate on different types. This ability to operate on multiple types reduces code duplication by allowing the same piece of code to be reused across the different types it can operate on. - Polymorphism comes in a variety of forms. What we are interested in at the moment is parametric polymorphism, meaning that we can write our code so that it is parameterized over what type it operates on.  -That is, we want to declare a type parameter T and replace int with T in the above code. -Then, when we want to call the function, we can specify the type for T and get the function we desire. C++ provides parametric polymorphism through templates. Templated Functions - We can write a templated function by using the keyword template followed by the template parameters in angle brackets (<>). - Unlike function parameters, template parameters may be types, which are specified with typename where the type of the parameter wo...

前端 优化代码体积

当我使用npm run build的时候,项目构建了很久。所以考虑用create-react-app网站下面的工具来缩小代码体积  Analyzing the Bundle Size https://create-react-app.dev/docs/analyzing-the-bundle-size 更改完成后 npm run build npm run analyze 可以看到以下的图片: 其中main.js有1.57mb 然后起服务 serve -s build -l 8000 进入到首页之后,打开network,查看js,发现main.js有500kb。这个500kb是已经用gzip压缩过了,但是却还有这么大。500*3=1500说明源文件有1.5mb左右 其中, antd占了25%, recharts占了13%, react-dom占了7.6%,dnd-kit占了2.8% 其中recharts用于统计页面,dnd-kit用于拖拽排序-编辑器页面。 所以在加载首页的时候,先不加载编辑页面和统计页面的js的话,体积会小很多。 路由懒加载 因为项目中,体积占比最大的是Edit和Stat页面(编辑和统计页面),所以考虑使用路由懒加载,拆分bundle,优化首页体积 router文件中,之前: import Edit from "../pages/question/Edit" ; import Stat from "../pages/question/Stat" ; 现在: const Edit = lazy (() => import ( "../pages/question/Edit" )); const Stat = lazy (() => import ( "../pages/question/Stat" )); 为了让生成的文件更加可读,可以改成下面这样: const Edit = lazy ( () => import ( /* webpackChunkName: "editPage" */ "../pages/question/Edit" ) ); const Stat ...

useMemo的使用场景

 useMemo是用来缓存 计算属性 的。 计算属性是函数的返回值,或者说那些以返回一个值为目标的函数。 有些函数会需要我们手动去点击,有些函数是直接在渲染的时候就执行,在DOM区域被当作属性值一样去使用。后者被称为计算属性。 e.g. const Component = () => { const [ params1 , setParams1 ] = useState ( 0 ); const [ params2 , setParams2 ] = useState ( 0 ); //这种是需要我们手动去调用的函数 const handleFun1 = () => { console . log ( "我需要手动调用,你不点击我不执行" ); setParams1 (( val ) => val + 1 ); }; //这种被称为计算属性,不需要手动调用,在渲染阶段就会执行的。 const computedFun2 = () => { console . log ( "我又执行计算了" ); return params2 ; }; return ( < div onClick = { handleFun1 } > //每次重新渲染的时候我就会执行 computed: { computedFun2 () } </ div > ); }; 上面的代码中,在每次点击div的时候,因为setParams1的缘故,导致params1改变,整个组件都需要重新渲染,也导致comptedFunc2()也需要重新计算。如果computedFunc2的计算量很大,这时候重新计算会比较浪费。 可以使用useMemo: const Com = () => { const [ params1 , setParams1 ] = useState ( 0 ); const [ params2 , setParams2 ] = useState ( 0 ); //这种是需要我们手动去调用的函数 const handleFun1 ...