首页 > 其他分享 >经典C语言笔试面试题目

经典C语言笔试面试题目

时间:2024-07-09 10:25:56浏览次数:17  
标签:int void 笔试 ++ C语言 char 面试 str printf

01. 请填写bool , float, 指针变量 与“零值”比较的if语句。

提示:这里“零值”可以是0, 0.0 , FALSE 或者“空指针”。
例如 int n 与“零值”比较的 if 语句为:
if ( n == 0 )
if ( n != 0 )

以此类推。

请写出 bool flag 与“零值”比较的 if 语句:
if(flag)
{

}

if(!flag)
{

}

请写出 float x 与“零值”比较的if 语句:
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
{

}

不可将浮点变量用“==” 或“!=” 与数字比较,应该设法转化成“>=” 或“<=” 此类形式。

请写出char *p 与“零值”比较的if 语句
if (p == NULL)
{

}
if (p != NULL)
{

}

02. 以下为Linux下的32 位C 程序,请计算sizeof 的值。

char  str[] = "Hello";
char *p = str ;
int   n = 10;
sizeof(str) = ?		// 6
sizeof(p) = ?		// 4
sizeof(n) = ?		// 4
void Func ( char str[100])
void * p = malloc( 100 );
sizeof(str) = ?		// 4
sizeof(p) = ?		// 4

03. 用变量a 给出下面的定义

  1. 一个有10个指针的数组,该指针是指向一个整型数的;
  2. 一个指向有10个整型数数组的指针;
  3. 一个指向函数的指针,该函数有一个整型参数并返回一个整型数;
  4. 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数;
1)int *a[10];
2)int (*a)[10]
3)int (*a)(int);
4)int (*a[10])(int)

04. 设有以下说明和定义:

typedef union
{
	long i;
	int k[5];
	char c;
} DATE;

struct data
{
	int cat;
	DATE cow;
	double dog;
} too;
DATE max;

则语句printf("%d",sizeof(struct date)+sizeof(max));的执行结果是:20

注解:
DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20。data 是一个struct, 每个变量分开占用空间. 依次为int4 +DATE20 + double8 = 32.所以结果是20 + 32 = 52.
当然在某些16位编辑器下, int 可能是2字节,那么结果是int2 + DATE10 + double8 = 20

05. 请问以下代码有什么问题:

int main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}

注解:
没有为str分配内存空间,将会发生异常问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,因为越界进行内在读写而导致程序崩溃。

06. 请问以下代码有什么问题:

char* s="AAA";
printf("%s",s);
s[0]='B';
printf("%s",s);

注解:
"AAA" 是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
cosnt char* s="AAA";然后又因为是常量,所以对s[0]的赋值操作是不合法的。

07. int (*s[10])(int) 表示的是什么?

int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param) 的函数。

08. c和c++ 中的struct有什么不同?

注解:
cc++中struct的主要区别是c中的struct不可以含有成员函数,而c++中的struct可以。c++structclass的主要区别在于默认的存取权限不同,struct默认为public,而class默认为private

09. 以下代码会出现什么问题?

void getmemory(char *p)
{
	p=(char *) malloc(100);
	strcpy(p,“hello world”);
}
int main( )
{
	char *str=NULL;
	getmemory(str);
	printf(“%s/n”,str);
	free(str);
	return 0;
}

程序崩溃,getmemory中的malloc不能返回动态内存,free()str操作很危险。

改进方案:

#pragma warning(disable:4996)
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void getmemory(char** p)
{
	*p = (char*)malloc(100);
	strcpy(*p, "hello world");
}
int main()
{
	char* str = NULL;
	getmemory(&str);
	printf("%s\n", str);
	free(str);
	return 0;
}

10. 以下代码产生什么结果?为什么?

char szstr[10];
strcpy(szstr,"0123456789");

注解:
长度不一样,出现段错误。szstr至少应该为11*(char)的长度

11. 给定结构体计算sizeof(A) = ?

struct A
{
	char t:4;
	char k:4;
	unsigned short i:8;
	unsigned long m;
};

sizeof(A) = 8
32linux系统为例。
t占了 4个bit,剩下 4 bit 可以被占用。char一共有8bit,一个字节。
k占了 4个bit,前面有 4 bit 正好可以占用。t和k一共占 8 bit,一个字节。
i占了 1个字节,空了一个字节下来。这里有 2 个字节。
long 需要4个字节,前面空的两个字节不够,由于 对齐原则,不能直接占后面的空间。
在这里插入图片描述

12. 给定结构体计算sizeof(name1) = ?

struct name1{
	char str;
	short x;
	int num;
};

sizeof(name1) = 8

13. 给定结构体计算sizeof(name2) = ?

struct name2{
char str;
int num;
short x;
};

sizeof(name1) = 12

14. 程序哪里有错误

wap( int* p1,int* p2 )
{
	int * p;
	*p = *p1;
	*p1 = *p2;
	*p2 = *p;
}

p 为野指针(指向一个已删除的对象或未申请访问受限内存区域的指针)

15. void-ptr-和voidptr-的结果是否相同其中ptr为同一个指针

(void *)ptr(*(void**))ptr值是相同的

16. 关于内存的思考题(1)你能看出有什么问题?

void GetMemory(char *p)
{
   p = (char *)malloc(100);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(str);
    strcpy(str, "hello world");
    printf(str);
}

请问运行Test 函数会有什么样的结果?

答:程序崩溃。因为GetMemory并不能传递动态内存,Test函数中的str一直都是NULL
strcpy(str, "hello world");将使程序崩溃。

改进方案:

void GetMemory(char **p)
{
   *p = (char *)malloc(100);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(&str);
    strcpy(str, "hello world");
    printf(str);
}

关于内存的思考题(2)你能看出有什么问题?

char *GetMemory(void)
{
    char p[] = "hello world";
    return p;
}
void Test(void)
{
    char *str = NULL;
    str = GetMemory();
    printf(str);
}

请问运行Test 函数会有什么样的结果?

答:可能是乱码。因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是NULL,但其原现的内容已经被清除,新内容不可知。

关于内存的思考题(3)你能看出有什么问题?

void GetMemory(char **p, int num)
{
    *p = (char *)malloc(num);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(&str, 100);
    strcpy(str, "hello");
    printf(str);
}

请问运行Test函数会有什么样的结果?

答:(1)能够输出hello;(2)内存泄漏

关于内存的思考题(4)你能看出有什么问题?

void Test(void)
{
    char* str = (char*)malloc(100);
    strcpy(str, "hello");
    free(str);
    if (str != NULL)
    {
        strcpy(str, "world");
        printf(str);
    }
}

请问运行Test函数会有什么样的结果?

答:篡改动态内存区的内容,后果难以预料,非常危险。
因为free(str);之后,str成为野指针,if(str != NULL)语句不起作用。
vs2019中编译通过,并成功打印word,这得益于系统并不会立刻被系统回收,free后会被某些程序托管,就好比。每次释放很小的空间,不停的释放,系统不停地回收,这并不合理,应该是达到一定的条件,才会被系统回收。但这块空间暂时已经不能被用户正常使用。

17. 关键字volatile有什么含意? 并给出三个不同的例子。

答:一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子:
1). 多线程应用中被几个任务共享的变量
2). 并行设备的硬件寄存器(如:状态寄存器)
3). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

18. const有什么用途?

【标准答案】
(1)可以定义const常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。

19. static有什么用途?

限制变量的作用域(static全局变量);
设置变量的存储域(static局部变量)。

20. 堆栈溢出一般是什么原因?

没有回收垃圾资源。

21. 如何引用一个已经定义过的全局变量?

可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

22. 用宏定义写出两数交换

#define Min(X, Y) ((X)>(Y)?(Y):(X))// 结尾没有 ;

23. 带参宏和无参宏的区别

                    带参宏              带参函数
处理时间             编译时               运行时
参数类型                无                需定义
程序长度              变长                  不变
占用存储空间            否                    是
运行时间      不占运行时间          调用和返回时占

24. A.c 和B.c两个c文件中使用了两个相同名字的static变量,编译的时候会不会有问题?这两个static变量会保存到哪里(栈还是堆或者其他的)?

static的全局变量,表明这个变量仅在本模块中有意义,不会影响其他模块。他们都放在静态数据区,但是编译器对他们的命名是不同的。如果要使变量在其他模块也有意义的话,需要使用extern关键字。

25. 用两个栈实现一个队列的功能?要求给出算法和思路

设2个栈为A,B, 一开始均为空.
入队:
将新元素push入栈A;

出队:
(1)判断栈B是否为空;
(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B
(3)将栈B的栈顶元素pop出;

26. 用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL

27. 请写出以下代码的输出

#include <stdio.h>
int main()
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b, c, d:%d, %d, %d", b, c, d);
return 0;
}
b, c, d: 10, 12, 120

28. 请计算 p1+5=?p2+5=?

unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
p1+5 = 0x801005;
p2+5 = 0x810020;

29. 请计算以下代码的输出

main()
{
	int a[5]={1,2,3,4,5};
	int * ptr=(int*)(&a+1);
	printf(“%d,%d”,*(a+1),*(ptr-1));
}
2, 5

30. 请计算以下代码的输出

int modifyvalue()
{ 
	return(x+=10);
}
int c hangevalue(int x )
{
	return(x+=1);
}
void main()
{
	int x =10;
	x++;
	changevalue(x);
	x++;
	modifyvalue();
	printf("First output:%dn",x);
	x++;
	changevalue(x);
	printf("Second output:%dn",x);
	modifyvalue();
	printf("Thirdoutput:%dn",x);
}
First output:12
Second output:13
Thirdoutput:13

31. 请写出以下代码的输出

void foo(void)
{
	unsigned int a = 6;
	int b = -20;
	(a+b> 6)? puts("> 6") : puts("<= 6");
}

输出是">6"
当表达式中存在有符号类型和无符号类型时所有的数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。

32. 编写strnpy()函数

已知strcpy函数的原型是char *strcpy(char *strDest,const char *strSrc);其中strDest是目的字符串,
strSrc 是源字符串。
1)不调用C++/C 的字符串库函数,请编写函数strcpy 。
2)strcpy 能把 strSrc 的内容复制到strDest,为什么还要char * 类型的返回值?

void my_strcpy(char* dest, char* sou)
{
	while (*sou != '\0')
	{
		*dest = *sou;
		dest++;
		sou++;
	}
}

优化:


#include<assert.h>
void my_strcpy(char* dest, char* sou)
{
	assert(dest && sou);
 
	while (*dest++=*sou++)
	{
		;
	}
}

写法二:


#include<assert.h>
char *my_strcpy(char* dest,const char* sou)
{
	assert(dest && sou);
	char* ret = dest;
	while (*dest++=*sou++)
	{
		;
	}
	return ret;
}

33. 写出二分查找的C代码

int binary_search(int* arr, int k ey, int n)
{
    int low =  0;
    int h igh = n - 1 ;
    int m id;
    while (low <= high)
    {
        mid = (high + low) / 2;
        if (arr[mid] > k)
            high = mid -1 ;
        else if (arr[mid] < k)
            low = mid + 1;
        else
            return mid;
    }
    return -1;
}

33. 编写一个C函数,该函数将给定的字符串转换成整数

int Invert(char* str) 
{ 
    int num =0; 
    while(*str!='\0') 
    { 
        int d igital=*str-48; 
        num=num*10+digital; 
        str=str+1; 
    } 
    return num; 
} 

34. 编写一个C函数,该函数将给定的整数转换成字符串

void IntToCharChange(int num,  char* pval) 
{ 
    char strval[100]; 
    int i , j; 
    int val0 = 0; 
    int val1 = 0; 
    val0 = num; 
    for(i=0; i<100; i++) 
    { 
        val1 = val0 % 10; //取余
        val0 = val0 / 10; // 取整
        strval[i] = val1 + 48;  // 数字—字符
        if(val0 < 10) 
        { 
            i++; 
            strval[i] = val0 + 48; 
            break; 
        } 
    } 
    for(j=0; j<=i; j++)  // 倒置
    pval[j] = strval[i-j]; 
    pval[j] = '\0'; 
}

35. 实现strcmp()函数

int mystrcmp(const c har* str1, const char* str2)
{
    assert((str1 != NULL) && (str2 != NULL));
    int ret = 0;
    while (!(ret = *(unsigned char*)str1 - * (unsigned char*)str2) && *str2)
    {
        str1++;
        str2++;
    }
    if (ret > 0)
        ret = 1;
    else if (ret < 0)
        ret = -1;
    return ret;
}

36. 编写一个C函数,该函数将给定的字符串逆序

void AntitoneValue(cha r* father, char* child) 
{ 
	int i ; 
	char source[100]; 
	int j = 0; 
	while(father[j]) //放入source ,[j] 为长度
	{ 
		source[j] = father[j]; 
		j++; 
		if(j > 99) 
		return; 
	} 
	source[j] = '\0'; 
	for(i=0; i<j; i++) 
	child[i] = source[j-i-1];  // 反序
	child[i] = '\0'; 
} 

37. 编写一个C函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值

int search(char* cpSource, intn , char ch)  // 起始地址,搜索长度,目标字符
{
    int i;
    for(i=0; i<n && *(cpSource+i) != ch; ++i);
    return i;
}

38 . 编写一个C函数,该函数在一个字符串中找到可能的最长的子字符串,该字符串是由同一字符组成

int C hildString(char*p)
{
    char *q =p;
    int s tringlen=0, i=0,j=1,len=0,maxlen=1;
    while(*q!=’\0’)          //不能用strlen, 求得长度stringlen
    {
        Stringlen++;
        q++;
    }
    while( i<  String len )
    {
        if(*(p+i)==*(p+j)& & j< St ri ngle n )
        {
            len++;                    // 统计子串长度
            i++;
            j++;
        }
        else
        {
            if(len>maxlen)           // 统计最大子串长度
            {
                maxlen=len+1;
                len=0;
            }
            else
            len=0;
            i++;
            j++;
        }
    }
    return   maxlen;
}

39. 怎么判断链表中是否有环

int testLinkRing(Link *head)
{
    Link *t1=head,*t2=head;
    while( t1->next && t2->next)
    {
        t1 = t1->next;
        if (NULL == (t2 = t2->next->next))
            return 0; // 无环
        if (t1 == t2)
            return 1;
    }
    return 0;
}

注解:
用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步;当p2 指针追上p1的时候,就表明链表当中有环路了

40. 编写一个C函数,该函数在将一个链表反向

void reverse(test* head)
{
    test* pe = head;
    test* ps = head->next;
    while(ps)
    { 
        pe->next = ps->next;
        ps->next = head;
        head = ps;
        ps =  pe->next;
    }
}

注解:
从第一个元素开始,ps指向他,将他ps指向头节点ps->next = head,将ps设为头节点head = ps; 操作下一个元素ps= pe->next;等,于是依次将每个元素翻到原头节点前面。

41. 编写一个C函数,该函数将二维数组行列元素互换,存到一个新数组

#include <stdio.h>
main()
{   
    int a [2][3]={{1,2,3},{4,5,6}};
    int b[3][2],i,j;
    printf("array a :\n");
    for(i=0;i<=1;i++)
    {   
        for(j=0;j<=2;j++)
        {   
            printf("%5d",a[i][j]);
            b[j][i]=a[i][j];
        }
        printf("\n");
    }    
    printf("array b :\n");
    for(i=0;i<=2;i++)
    {   
        for(j=0;j<=1;j++)
        printf("%5d",b[i][j]);
        printf("\n");
    }
}

42. 编写一个C函数,该函数实现输入一行字符,统计其中有多少个单词

#include <stdio.h>
main()
{   
char str i ng[81];
int i,num=0,word=0;
char c;
gets(string);
for(i=0;(c=string[i])!='\0';i++)
if(c==' ')  
word=0;
else if(word==0)
{   
word=1;  num++;   }
printf("There are %d word s in the line\n",num);
}

43. 编写一个C函数,该函数实现计算字符串中字串出现的次数

int main()
{
    char str1[20],str2[20],*p1,*p2;
    int sum=0;
    printf("please input two strings\n");
    scanf("%s%s",str1,str2);
    p1=str1;p2=str2;
    while(*p1!='\0')
    {
        if(*p1==*p2)
        {
            while(*p1==*p2&&*p2!='\0')
            {
                p1++;
                p2++;
            }
        }
        else
        p1++;
        if(*p2=='\0')
        sum++;
        p2=str2;
    }
    printf("%d",sum);
    getch();
}

44. 写一个内存拷贝函数memcpy,不用任何库函数

void* memcpy(void* pvTo, const void* pvFrom, size_t size)
{
assert((pvTo != NULL) && (pvFrom ! = NULL));
byte* pbTo= pvTo;
byte* pbFrom = pbFrom;
while (size-- >  0)
{
*pbTo++ = *pbFrom++;
}
return pvTo;
}

45. 有两个磁盘文件A和B, 各存放一行字母,要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件C 中。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp(const void* a, const void* b)
{
	return *(char*)a - *(char*)b;
}

int main()
{
	// 读文件
	FILE* f_read_A = fopen("A.txt", "r");
	FILE* f_read_B = fopen("B.txt", "r");

	if (f_read_A == NULL || f_read_B == NULL)
	{
		return 0;
	}

	char buf_a[100] = { 0 };
	char buf_b[100] = { 0 };
	int a = 0, b = 0;
	char ch;
	while ((ch = getc(f_read_A)) != EOF)
	{
		buf_a[a++] = ch;
	}

	while ((ch = getc(f_read_B)) != EOF)
	{
		buf_b[b++] = ch;
	}

	char* buf_c = strcat(buf_a, buf_b);
	qsort(buf_c, strlen(buf_c), sizeof(char), cmp);
	printf("%s\n", buf_c);

	//写文件
	FILE* f_write_C = fopen("C.txt", "w");
	if (f_write_C == NULL)
	{
		return 0;
	}

	for (int i = 0; i < strlen(buf_c); i++)
	{
		fputc(buf_c[i], f_write_C);
	}

	fclose(f_read_A);
	fclose(f_read_B);
	fclose(f_write_C);

	return 0;
}

标签:int,void,笔试,++,C语言,char,面试,str,printf
From: https://blog.csdn.net/Young_Pro/article/details/140263834

相关文章

  • 大模型算法方向实习会经常提问哪些问题?看完手撕面试官拿下offer!
    现互联网研发一枚,曾拿过多个算法/研发岗SPoffer,简要介绍一下大模型算法岗面试内容和如何准备面试。大模型算法岗的面试内容,实际上可以拆解成两部分,一是算法岗通用的面试内容,二是大模型专有相关部分。算法岗通用面试内容这部分内容很重要,因为通用的面试内容可以适用于不同......
  • C++入门(C语言过渡)
    文章目录前言一、C++关键字二、命名空间三、C++输入&输出四、缺省参数五、函数重载六、引用七、inline八、nullptr总结前言C++是一种通用的、高级的、静态类型的编程语言,它在20世纪80年代由丹尼斯·里奇创建的C语言基础上发展而来。以下是C++发展的一些重要里程碑。......
  • SVN 80道面试题及参考答案(2万字长文)
    目录解释SVN的全称和主要功能。SVN与CVS相比,有哪些主要改进?描述SVN的工作流程。什么是版本库(repository)?它存储了什么?解释工作副本(workingcopy)的概念。SVN如何处理文件的版本控制?SVN中的“commit”是什么意思?解释“update”操作的作用。如何查看一个文件的历史版......
  • 那些年背过的面试题——JVM篇
    本文是技术人面试系列JVM篇,面试中关于JVM都需要了解哪些基础?一文带你详细了解,欢迎收藏!JVM内存划分1、JVM运行时数据区域堆、方法区(元空间)、虚拟机栈、本地方法栈、程序计数器。Heap(堆):对象的实例以及数组的内存都是要在堆上进行分配的,堆是线程共享的一块区域,用......
  • 嵌入式C语言面试相关知识——CPU、进程和线程相关(相关问题很多,会经常过来更新)
    嵌入式C语言面试相关知识——CPU、进程和线程相关一、博客声明二、自问题目——CPU相关1、什么是中断?如何处理中断?2、解释上下文切换(ContextSwitch)?3、在嵌入式中如何优化CPU使用?三、自问题目——进程相关1、什么是进程?2、嵌入式系统中进程和线程的区别是什么?3、在嵌......
  • 嵌入式学习——C语言概述(编译原理)
    一、计算机的组成部分输入设备、内存、cpu(运算器、控制器)、外存储器、输出设备二、C语言编译的步骤(面试重点)1、预处理:宏指令的替换(#include<stdio.h>等等)、删除注释、添加行号等。      例如:gcc-Ehello.c-ohello.ihello.i文件内容:    这段代码就......
  • 大厂面试必备系列:一文彻底搞懂 Cglib 代理
    前言大家在面试中经常被问到Cglib和JDK动态代理有啥区别?然后每次回答都是Cglib通过创建目标类的子类来实现代理。这个回答当然是对的,但是太敷衍了,没得加分,今天我带大家深入了解下。最佳实践直接上案例案例地址:https://github.com/zhuangjiaju/easytools/blob/ma......
  • Python面试题-8
    41.请解释Python中的切片操作。在Python中,切片(Slicing)是一种获取序列(如字符串、列表、元组等)的子集或部分的操作。切片操作使用方括号[],并且可以在方括号中指定开始索引、结束索引和步长。其基本语法如下:sequence[start:end:step]start是切片开始的索引,默认为0(序列的......
  • 【js面试题】深入理解尾递归及其在JavaScript中的应用
    面试题:举例说明尾递归的理解,以及应用场景引言:在编程中,递归是一种常见的解决问题的方法,它允许函数调用自身来解决问题。然而,递归如果不当使用,可能会导致栈溢出错误,特别是在处理大量数据时。尾递归是一种特殊的递归形式,它能够优化递归调用,避免栈溢出的问题。本文将深入探......
  • 必经之路-美团2023笔试(codefun2000)
    题目链接必经之路-美团2023笔试(codefun2000)题目内容塔子哥的班主任最近组织了一次户外拓展活动,让班里的同学们一起去爬山。在路上,塔子哥看到了一棵漂亮的树,他对这棵树产生了浓厚的兴趣,开始观察并记录这棵树的一些特征。塔子哥发现这棵树有n个节点,其中有一条边被特......