日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言,你真的弄懂了么?

發布時間:2025/3/11 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言,你真的弄懂了么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

程序(來源 ):

?

#include <stdio.h>int main(void) {int x[4];printf("%p\n", (void*) (x));printf("%p\n", (void*) (x + 1));printf("%p\n", (void*) (&x));printf("%p\n", (void*) (&x + 1)); }

?假設x的地址為n,那么輸出為:

?

n n+4 n n+16

?window下使用gcc編譯輸出結果:

?

0x22cd44 0x22cd48 0x22cd44 0x22cd54

?前三個還比較好理解,最后一行中&x實際表示是一個類型為int (*)[4]類型的指針,所以&x+1后地址增加16。

?有一個和上面類似的程序(源自《C語言深度剖析》,可以在網上搜索下載到):

#include <stdio.h>int main(void) {int a[] = {1,2,3,4,5};int *p = (int *)(&a+1);printf("%d %d\n",*(a+1),*(p-1));return 0; }

? 此程序輸出結果為2,5

類似的還有個程序:

#include <stdio.h>int main(void) {int a[] = {1,2,3,4,5,6,7,8,9,10};int (*p1)[3] = &a;int (*p2)[4] = a;printf("%d %d\n",*(*(p1+1)+1),*(*(p2+2)+1));return 0; }

? 該程序編譯時會提示警告(p1和p2初始化采用不兼容的指針類型)。

? 這里,p1和p2都是數組指針。p1指向有三個元素的整型數組,p2指向有四個元素的整形數組。

? 數組指針p1類似于一個二維數組b[][3],而根據二維數組b[i][j]可以表示成*(*(b+i)+j)的形式。所以*(*(p1+1)+1)相當于二維數組b[][3]中的b[1][1],因而對應于a[4],所以輸出結果為5,類似的可以得出另一個指針的輸出結果。

所以整個輸出結果為5,10

同樣,還有個程序:

#include <stdio.h> int main(void) {int a[4] = {1,2,3,4};int *ptr1 = (int*)(&a+1);int *ptr2 = (int *)((int)a+1);printf("%x,%x\n",ptr1[-1],*ptr2);return 0; }

? ptr1[-1]的值(跟上面的例子的情況類似)為4

? 而*ptr2的值則根據處理器的不同而可能有不同的結果(參見大端模式和小端模式 endianness )

? 如果為小端模式(例如intel x86兼容處理器,8051,avr等),那么*ptr2(注意使用題目中使用了%x輸出格式)輸出結果為2000000

? 如果為大端模式(例如motorola 68k,powerpc,IBM sys/360等),那么*ptr2輸出結果為100

判斷處理器使用什么模式,可以使用下面函數進行檢測(相關鏈接 ):

/*little endian when return 1,else big endian*/ int CheckEndian() {union{int i;char c;}e;e.i = 1;return (e.c == 1); }

? 如果使用大端模式,那么數組a在內存中表示(十六進制)為 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04

ptr2指向第二個00,所以為00 00 01 00(即0x100)

? 如果是小端模式,那么數組a在內存中表示為01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00,ptr2指向第一個00,所以其指向內容為00 00 00 02,由于使用了小端模式,所以需要顛倒過來表示即02000000(也即0x2000000).

接著是一些二維數組和二級指針的一些例子(同樣源自《c語言深度剖析》):

?

#include <stdio.h>int main(void) {int a[3][2]={(1,2),(3,4),(5,6)};int *p;p = a[0];printf("%d\n",p[0]);return 0; }

?編譯后運行,結果為2,因為圓括號內的使用了逗號表達式,二維數組a的初始化相當于int a[3][2]={2,4,6};

?

#include <stdio.h> int main(void) {int a[5][5];int (*p)[4];p = a;printf("a_ptr=%#p,p_ptr=%#p\n",&a[4][2],&p[4,2]);printf("%p,%d\n",&p[4][2]-&a[4][2],&p[4][2]-&a[4][2]);return 0; }

?編譯后運行,結果為

a_ptr=0X0022FF70,p_ptr=0X0022FF38 FFFFFFFC,-4

?這是因為二維數組實際上仍然用一維數組來表示。而int (*p)[4]相當于把a的一維數組表示又轉化成二維數組[][4],這樣&p[4][2]相當于p+4*4+2,&a[4][2]相當于p+4*5+2,所以二者相減結果為-4.

?

接著是幾個內存分配的程序(源自《高質量程序設計指南--c++/c語言》)

(1)

#include <stdio.h>void getmemory(char *p) {p = (char*)malloc(100*sizeof(*p));} int main(void) {char *str = NULL;getmemory(str);strcpy(str,"hello,world");printf("%s\n",str);return 0; }

? 編譯運行后程序會發生崩潰,因為getmemory只是將NULL值傳給參數p,然后又給p分配了100個字節空間,對str沒有任何改變。由于str仍未NULL,所以對空串進行串拷貝會發生崩潰。

(2)

#include <stdio.h>char *getmemory(void) {char p[] = "hello,world";return p; } int main(void) {char *str = NULL;str = getmemory();printf("%s\n",str);return 0; }

?編譯運行該程序,其輸出結果為亂碼。

這是因為C語言中棧幀布局可知,getmemory被調用后,會在棧上分配數組p來存放"hello,world"字符串并返回該串地址,但是在getmemory返回后,在棧上分配的數組部分已經變成無效狀態,此時調用printf函數,就會覆蓋掉原來數組p中的內容。但是輸出串地址仍是以前的地址,所以可能輸出亂碼。

(3)

#include <stdio.h>void getmemory(char **p, int num) {*p = (char*)malloc(num); } int main(void) {char *str = NULL;getmemory(&str,100);strcpy(str,"hello,world");printf("%s\n",str);return 0; }

?編譯運行該代碼會輸出”hello,world",但是該程序沒有將分配空間釋放,所以可能會產生內存泄漏

(4)

#include <stdio.h>void test(void) {char *str = (char*)malloc(100);strcpy(str,"hello");free(str);if(str != NULL){strcpy(str,"world");printf("%s\n",str);} } int main(void) {test();return 0; }

?編譯運行該程序后,可能產生非常危險的后果。因為前面給str分配空間并釋放,但是并沒有將str設置為NULL,因而str成為“野指針”,下面還要繼續對str原來位置復制一個串"world"并輸出,這就成了篡改堆中內容,可能帶來非常嚴重的后果。

?

?

接下來是一個要求不用循環和條件語句輸出1到1000的所有整數(來源 )。

(方法1):該方法會產生一個錯誤(除0故障),但能輸出正確結果

?

#include <stdio.h> #define MAX 1000 int boom; int foo(n) {boom = 1 / (MAX-n+1);printf("%d\n", n);foo(n+1); } int main() {foo(1); }

?(方法二):

?

#include <stdio.h> #include <stdlib.h>void f(int j) {static void (*const ft[2])(int) = { f, exit };printf("%d\n", j);ft[j/1000](j + 1); }int main(int argc, char *argv[]) {f(1); }

?這段代碼可以簡化為:

?

#include <stdio.h> #include <stdlib.h>void main(int j) {printf("%d\n", j);(&main + (&exit - &main)*(j/1000))(j+1); }

? 運行此程序時,由于不帶任何參數,所以j的初始值為1(相當于argc參數,只是這里變量名換一下而已,不影響程序的執行),然后輸出1,下一句中j/1000值為0(j為1-999之間任意整數時其值均為0),所以相當于執行(&main)(2),這是一個函數指針調用,然后輸出2,繼續執行下去直至j為999時,會調用(&main)(1000),此時輸出1000,j/1000值變為1,所以下一步調用(&main+(&exit-&main))(1001),即exit(1001),此時使用exit跳出函數的執行。

?

?

不使用中間變量交換兩個整型變量的值,代碼如下:

int x,y; x=x^y; y=x^y; x=x^y;

?

Duff's device :

?

send(to, from, count)register short *to, *from;register count;{register n=(count+7)/8;switch(count%8){case 0: do{ *to = *from++;case 7: *to = *from++;case 6: *to = *from++;case 5: *to = *from++;case 4: *to = *from++;case 3: *to = *from++;case 2: *to = *from++;case 1: *to = *from++;}while(--n>0);}}

?這個代碼格式是老的代碼格式。具體講解見上面的鏈接。

?

檢查一個字符串(名稱為s1)是否是另外一個字符串(名稱為s2)的旋轉版本(來源 )。例如"stackoverflow"的旋轉版本字符串有: "tackoverflows",“overflowstack"等。

算法實現方法如下:

(1)確定兩個串長度相等

(2)將s1和s1連接起來,檢查s2是否是連接后的串的字串

#include <stdio.h> #include <stdlib.h> #include <string.h> int IsRotation(char s1[], char s2[]) {int len1 = strlen(s1),len2=strlen(s2);char *str = malloc((len1+len1+1)*sizeof(char));if(len1 != len2)return 0;if(str == NULL){fprintf(stderr,"error while allocating space\n");return -1;}if(strcpy(str,s1) == NULL || strcat(str,s1) == NULL){fprintf(stderr,"error while copying or concatenate string s1 to str\n");return -1;}if(strstr(str,s2) != NULL)return 1;return 0; }

?這段代碼是我自己寫的,可能有不完善的地方。當執行中出錯時返回-1,如果是旋轉串則返回1,否則返回0.

總結

以上是生活随笔為你收集整理的C语言,你真的弄懂了么?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。