Comment: 18 Classic questions in C language

Source: Internet
Author: User
Tags define null first string


C Language 18 Classic Questions answer this everybody has seen, oneself also looked carefully again, in addition, will a little sentiment raises a bit.


1. What is the problem with this initialization? Char *p = malloc (10); The compiler prompts for "illegal initialization" and so on.
A: Is this declaration a static or non-local variable? function calls can only appear in the initial formula of an automatic variable (that is, a local non-static variable). Because the address of a static variable must be determined during compilation and the memory address requested by malloc () is determined at run time.

Comment: GCC compilation will not error. However, this is a bad programming habit, and even if you know the size of the memory, it is common to use a macro definition to identify the fixed memory size that needs to be allocated. This is both easy to understand and provides the basis for future code modification and porting.


2. Is the *p++ self-increment p or the variable that p points to?
A: the suffix + + and--operator is inherently higher in priority than the prefix-to-eye operation, so *p++ and * (p++) are equivalent, it increases p and returns the value pointed to by the P increment. To increment the value that P points to, use the (*p) + + and use ++*p if the order of the side effects does not matter.

Comment: The program is executed according to the logical relationship fixed by the operator. To facilitate comprehension and reading, it is a programming habit to use () as much as possible to avoid understanding the two semantic problems that arise when coding.


3. I have a char * type pointer that just happens to point to some type int variables, and I want to skip them. Why the following code ((int *) p) + +; No way?
A: In C language, type conversion means "treat these bits as a different type, and do the corresponding treatment"; This is a conversion operator, which, by definition, can only generate an rvalue (rvalue). The right value can neither be assigned nor be increased with + +. (if the compiler supports such an extension, it is either an error or a non-standard extension that is intentionally made.) To achieve your purpose can be used: p = (char *) ((int *) p + 1), or, because P is char * type, directly with P + = sizeof (int);

Review: The GCC compiler moves the corresponding type-size bytes to the + + operation based on the size of the pointer's pointing type.


4. is a null pointer and an uninitialized pointer a thing?
A: A null pointer is conceptually different from an uninitialized pointer: A null pointer ensures that no object or function is pointed to, and a pointer that is not initialized may point to anywhere.

Comment: Any pointer must be initialized if it is not determined that the pointer purpose can be initialized to a null value. The usual programming in the military, of course, in the optimization code will have a clear explanation and explanation.


5. Can i indicate a null pointer with a "%"?
A: According to the language definition, constant 0 in the context of the pointer is converted to a null pointer at compile time. In other words, when initializing, assigning, or comparing,
If one side is a pointer-type value or expression, the compiler can determine that the other side of the constant 0 is a null pointer and generates the correct null pointer value. So the code snippet below is completely legal:
char *p = 0;
if (P! = 0)

However, the parameters passed into the function are not necessarily treated as a pointer environment, so the compiler may not recognize the unmodified 0 "representation" pointer.
Generating a null pointer in the context of a function call requires an explicit type conversion, forcing 0 to be treated as a pointer.
For example, the Unix system calls Execl to accept a variable-length character pointer argument that ends with a null pointer. It should be called correctly as follows:
Execl ("/bin/sh", "sh", "-C", "Date", (char *) 0);
If the (char *) Conversion of the last argument is omitted, the compiler has no way of knowing that this is a null pointer, which is passed as a 0. (Note that many Unix manuals are mistaken in this example.) )


Summary:
==========================|=============================
|| can be used without modification of 0 | Type conversions that need to be displayed | |
|| ------------------------|---------------------------||
|| * Initialize | * Function call, no prototype in scope | |
|| * Assign Value | * variable arguments in variable parameter function call | |
||                           * comparison | ||
||                           * Fixed arguments for function calls | ||
||                           And there are prototypes within the scope | ||
==========================|=============================

There are two simple rules you must follow:
1) When you need null pointer constants in the source code, use "0" or "null".
2) If "0" or "NULL" is used as a parameter in a function call, convert it to the type of pointer required by the called function

Comment: It is recommended to use a null value, universal and easy to judge that the variable is a pointer. See/usr/include/linux/stddef.h, Linux under C language null defined as # define NULL ((void *) 0).


6. Since the array reference will degenerate into a pointer, if ARR is an array, then what is the difference between arr and &arr?
Answer: The difference is the type:
In standard C, &arr generates a pointer to the "T-array", pointing to the entire array.
In all C compilers, a simple reference to an array (not including the & operator) generates a pointer to the pointer type of T, pointing to the first member of the arrays.

Rating: int array[100];
About the problem of the address of the array name, because the arrays name is the right value, originally &array is not legal, many early compiler is the designation &array is illegal, but later c89/c99 think that the array conforms to the semantics of the object, to an object to take the address is reasonable, therefore, &array is also allowed, starting with the integrity of the objects being maintained. However, the meaning of &array is not to address an array name, but to take an address on an array object, and because of this, the array is the same as the address value represented by &array, and sizeof (array) should be with sizeof (& Array), because sizeof (&array) represents the length of an array object.

Note, however, that the type of array and &array are different. Array is a pointer, and &array is a pointer to the array int [100]. Array is equivalent to &array[0], and &array is a pointer to int[100], and the type is int (*) [100]. The type is: type (*) [array size], so the &a+1 size is: First address +sizeof (a).


7. How do I declare an array pointer?

A: Usually, you don't need to. When people casually mention array pointers, they usually think of pointers to the first element of it.
Consider using a pointer to an element of an array, rather than a pointer to an array. The array of type T transforms into a pointer of type T, which is convenient;
Use subscript or increment on the pointer of the result to access individual members of the array. A real array pointer, when using subscript or increment, skips the entire array,
This is usually useful only when manipulating arrays of arrays. If there's one more thing to use. If you really need to declare a pointer to the entire array,
Use a similar "int (*AP) [N];" Such a declaration. where n is the size of the array. If the size of the array is unknown, you can omit n in principle, but the resulting type
"Pointer to an array of unknown size" is useless.


Comment: An array is a collection of data, which is often used for algorithms or fixed parameters. If you have such a collection of data, it is not as easy to refer to the name of the data collection as it is to use the pointer. What the general application really cares about is the elements inside the array. therefore pointers to array elements are more important.



8. When I pass a pointer to a function that accepts pointers to a two-dimensional array, the compiler makes an error, what is this?
A: The rule that the array is degenerate into a pointer cannot be applied recursively. An array of arrays (that is, a two-dimensional array in C) is degenerate to an array pointer, not a pointer to pointers.
Array pointers are often confusing and need to be treated with care; If you pass a two-bit array to the function:
int Array[nrows][ncolumns];
f (array);
Then the declaration of the function must match:
void f (int a[][ncolumns])
{ ... }
Or
void f (int (*AP) [ncolumns])/* AP is an array of pointers */
{ ... }
In the first declaration, the compiler makes the usual implicit conversion from "array of arrays" to "pointers to arrays"; The pointer definition in the second form is obvious.
Because the tuned function does not assign an address to an array, it does not need to know the total size, so the number of rows nrows can be omitted. But the width of the array is still important,
So the Levi degree Ncolumns (for three-dimensional or multidimensional arrays, related dimensions) must be preserved.
If a function is already defined as a pointer to a pointer, it is almost certain that it is meaningless to pass directly to it in a two-dimensional array.

Comments: The function of the main parameter is the transfer of value and address: The main value is the transfer of variables, the main address is the transfer of addresses. According to the object's perspective, a variable and address are an object, and an array is an object, and this object cannot be passed in as a function parameter.


9. My strcat () is not working. I tried char *s1 = "Hello,"; Char *s2 = "world!"; Char *s3 = strcat (s1, S2); But I got a strange result.
A: The main problem here is that there is no proper allocation of space for the connection result. C does not provide a string type that is automatically managed.
The C compiler allocates space only for objects explicitly mentioned in the source code (for strings, which include character arrays and string constants).
The programmer must allocate enough space for the result of a run-time operation such as a string connection,

This can often be done by declaring an array or by calling malloc (). strcat () does not make any allocations; The second string is attached to the first one.
Thus, one solution is to declare the first string as an array:
Char s1[20] = "Hello,";
Because strcat () returns the value of the first parameter, in this case S1, S3 is actually superfluous; After the strcat () call, S1 contains the result.
The strcat () call in the question actually has two problems: the string constant pointed to by S1, except that there is not enough space to put the concatenated string,
It doesn't even have to be written.


Comment: The main problem here is that there is no clear understanding of the string constants and Strcat in the basic programming of C language. First, the string constants are placed in the Rodata segment, and the string array is placed in the Rwdata segment, and secondly, the strcat is appending the string src points to the null end of the dest, and an unknown exception occurs when the dest is out of bounds.

Char *strcat (char *dest, const char *SRC);
The strcat () function appends the SRC string to the dest string, overwriting the terminating null byte ('% ') at the end  of Dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must has enough space for the result. If Dest is not large enough, program behavior is unpredictable; Buffer overruns is a favorite avenue for attacking secure programs.

Reference: Redis Open Source reading note Six (SDS module), SDS Sdscat (SDS s, const char *t);



10. So what is the correct way to return a string or other collection?
A: The return pointer must be a statically allocated buffer, or a buffer passed in by the caller,
or the memory obtained with malloc (), but not a local (automatic) array.

Comment: The scope of the local array is inside the function, when the function returns, the memory area will be freed, and the returned array address points to invalid data, so the returned must be the memory space of the caller or the scope of the above.


11. I have a program that allocates a lot of memory and then releases it. But from the operating system, the memory occupancy rate did not go back.
A: Most malloc/free implementations do not return the freed memory to the operating system, but are reserved for subsequent malloc () use by the same program.

Review: The PTMALLOC mechanism adopted by the GLIBC library, which acquires or frees system memory through Mmap and Mumap, while in practice, malloc and free do not interact directly with the system, which primarily maintains memory resources in the process, so, although free memory is available, From the ptmalloc mechanism, free resources are not immediately released to the operating system.


What is the difference between calloc () and malloc ()? Is it safe to use the 0 fill function of calloc? can free () release the memory allocated by Calloc (), or do you need a cfree ()?
Answer: Calloc (M, n) is essentially equivalent to:
p = malloc (M * n);
memset (p, 0, M * n);
Padding 0 is all zeros, so it is not guaranteed to generate a useful null pointer value or a floating-point zero value free ()

Can be safely used to release calloc () allocated memory.

Review: malloc and calloc mainly consider the cost of their performance on memset.


13. I think my compiler has a problem: I noticed that sizeof (' a ') is 2 instead of 1 (that is, not sizeof (char)).
A: It may be surprising that character constants in C are type int, so sizeof (' a ') is sizeof (int), which is another place different from C + +.

Comment: This is just a compiler definition problem, it is very interesting indeed. The 64-bit system sizeof (int) is 4, and the 32-bit system sizeof (int) is 2.
$ cat Main.c#include <stdio.h>int main () {        char A;        printf ("sizeof (a) =%d\n", sizeof (a));        printf ("sizeof (' a ') =%d\n", sizeof (' a '));        printf ("sizeof (char) =%d\n", sizeof (char));        printf ("sizeof (int) =%d\n", sizeof (int));        return 0;} $ gcc main.c[email protected]:~/test$./a.outsizeof (a) = 1sizeof (' a ') = 4sizeof (char) = 1sizeof (int) = 4$ g++ main.c$./A. Outsizeof (a) = 1sizeof (' a ') = 1sizeof (char) = 1sizeof (int) = 4



14. Why declare extern int f (struct x *p); Reported a strange warning message, "struct x declaration in the argument list"?
A: Contrary to the usual scope rules of C, the first declaration (or even mention) of a structure in a prototype cannot be compatible with other structures in the same source file.
It goes out of scope at the end of the prototype. To solve this problem, put such a declaration before the prototype of the same source file:
struct x;
It provides a declaration of an incomplete struct x within the scope of the file, so that subsequent declarations using struct X can at least determine that they are referencing the same struct x.


Comment: Minimize the extern definition in your code, which is something that is more disruptive to modularity and increases coupling, just as programming does not encourage the use of goto statements.

15. I don't understand why I can't do this like this. Constants are used in initialization and array dimensions: const int n = 5; int a[n];
A: The true meaning of the const qualifier is "read-only"; The object to which it is qualified is the object that the runtime (as usual) cannot be assigned to.
Therefore, the value of a const-qualified object is not exactly a true constant.
C and C + + are not the same at this point. If you need to really run a constant amount, use a predefined macro #define (or enum).

Comment: const and define. Both can be used to define constants, but the const definition defines the type of the constant, so it is more accurate. #define只是简单的文本替换, in addition to defining constants, you can also define some simple functions.


16. Can I define main () as void to avoid disturbing the "main no return value" warning?
Answer: No. Main () must be declared to return int with no arguments or accept two parameters of the appropriate type.
If you call exit () but you still have a warning message, you may need to insert a redundant return statement
(or use some kind of "not arrived" directive, if any). Many books irresponsibly use void Main () in the example,
And claim that this is true. But they were wrong.

Comment: the void main () in GCC can be defined and used, but from a normal point of view, main needs an int to return, ensuring that the command line execution command has the correct $? return value.

What's the use of #pragma?
A: The #pragam directive provides a single, well-defined "rescue pod" that can be used as a variety of (non-portable) implementation-related controls and extensions:
source Table control, structure compression, warning removal (like lint's old/* notreached */note), etc.

Comment: In all pre-processing directives, the #Pragma directive may be the most complex, its role is to set the state of the compiler or to instruct the compiler to complete some specific actions. #pragma指令对每个编译器给出了一个方法, given the unique characteristics of the host or operating system, while maintaining full compatibility with the C and C + + languages. By definition, the compilation instructions are proprietary to the machine or operating system and are different for each compiler.


What does "#pragma once" mean? I saw it in some header files.
A: This is an extension of some preprocessor implementations to make the header file self-identifying; It is equivalent to the #ifndef technique, but less transplant.

Comments: The format is generally: #pragma Para. Where para is the parameter, here are some common parameters Message,code_seg,data_seg,once,hdrstop,resource,warning,comment,disable,region,pack

Comment: 18 Classic questions in C language

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.